Hedging Renewable Energy Investments with Bitcoin Mining

Authors: Bastian-Pinto, C., Araujo, F. VdS., Brandão, L. E. T., Gomes, L. L.

Abstract Renewable energy sources such as wind power are increasing their share of the world energy matrix. Nonetheless, wind farms projects are subject to variations in output due to climate conditions and to price volatility if they choose to anticipate construction to sell their energy in the short term markets. In order to create incentives for early investment, we show that wind farm investors can hedge electricity price risk by simultaneously investing in a cryptocurrency mining facility that uses electricity as input to produce newly minted Bitcoins to sell in the market. Given that electricity and Bitcoin prices are mostly uncorrelated, the ability to switch outputs between these two assets depending on their relative prices, allows the firm to maximize revenues and minimize losses. We develop a numerical application where we apply the real options approach to model a wind farm that chooses to anticipate construction in order to sell energy in the short term market for up to four years prior to entering into its long term energy sales commitment. Given that this power plant also invests in a Bitcoin mining facility, whenever the price of the Bitcoins created is higher than the market price of electric power, the firm will choose to operate the mining facility. Otherwise, it will sell its energy to the market. The short-term energy price and Bitcoin price/mining-difficulty ratio are modeled as two distinct stochastic diffusion processes. The results show that the option to switch outputs significantly increases the generator’s revenue while simultaneously decreasing the risk.

Keywords: real options, switch option, renewable energy production, cryptocurrency mining, bit-spread

This work presents the calculations done for the article referenced above. The following calculations use parameters for the diffusion of stochastic variables that have been defined in the paper. All the code was run in RStudio using the version of the software below.

Software version

R.version
               _                           
platform       x86_64-w64-mingw32          
arch           x86_64                      
os             mingw32                     
system         x86_64, mingw32             
status                                     
major          4                           
minor          0.1                         
year           2020                        
month          06                          
day            06                          
svn rev        78648                       
language       R                           
version.string R version 4.0.1 (2020-06-06)
nickname       See Things Now              

Setting of the environment

# Sets the number of series used in the MonteCarlo Simulation
NSeries <- 50000 

# Used to set BTC production cap and calculate investment
numberBTCMiners <- 1750 

# Used to determine the starting value of BTC diffusion process
# Possible values: "deterministic", "triangular", "regression"
# Fine tuning can be done in the BTCStart section; overriden if excelVersion = TRUE
BTCStartType <- "triangular" 

# Set TRUE to sell excedent of power production at PLD prices
# Always FALSE if excelVersion is TRUE
extraProduction <- TRUE 

# Measure mu and sigma of BTC diffusions statistics
# Can slow down calculations
testBTCDiffusion <- FALSE 

# Set TRUE to save histograms in PDF format
# See also other variables to be set at the chart generation command line
savePDF <- FALSE 

# Global Chart Configurations
# Used to resize plots
require(repr) 
Loading required package: repr
package 㤼㸱repr㤼㸲 was built under R version 4.0.2
options(repr.plot.width=8, repr.plot.height=3) 
# Used for triangular distribution when defined by BTCStartType
require(extraDistr)
Loading required package: extraDistr
package 㤼㸱extraDistr㤼㸲 was built under R version 4.0.2
# Used to print tables inside the R Notebook
require(knitr)
Loading required package: knitr

Local functions definition

The first set of local functions are used to create the diffusion of the stochastic variables and their deterministic counterparts.

## Diffusion Functions ##

PLD_Diffusion <- function(start, len, n, RevertingMean, Volatility, Eta, Max) {
    # Diffusion1 <- RevertingMean*exp(-Volatility^2/(4*Eta))
    Diffusion2 <- exp(-Eta)
    Diffusion3 <- (log(RevertingMean)-Volatility^2/(2*Eta))*(1-Diffusion2)
    Diffusion4 <- Volatility*sqrt((1-Diffusion2^2)/(2*Eta))
    
    x = matrix(NA, nrow=(len+1), ncol=n)
    x[1, ] = start
    
    for(i in 2:(len+1)){
        x[i, ] = exp(log(x[i-1, ])*Diffusion2+Diffusion3+Diffusion4*rnorm(n,0,1))
        x[i, x[i, ] > Max] = Max
    }
    return(x)
}

PLD_Deterministic <- function(start, len, RevertingMean, Volatility, Eta, Max) {
    Diffusion1 <- log(RevertingMean)-Volatility^2/(2*Eta)
    Diffusion2 <- Volatility^2/(4*Eta)
    
    x = rep(NA, len)
    
    for(i in 1:len){
        x[i] = min(Max, exp(log(start)*exp(-Eta*i)+Diffusion1*(1-exp(-Eta*i))+Diffusion2*(1-exp(-2*Eta*i))))
    }
    return(c(start, x))
}

BTC_Diffusion <- function(start, len, n, mu, sigma) {
    x = matrix(NA, nrow=(len+1), ncol=n)
    x[1, ] = start
    
    for(i in 2:(len+1)){
        x[i, ] = x[i-1, ]*exp(rnorm(n, mu-sigma^2/2, sigma))
    }
    return(x)
}

BTC_Deterministic <- function(start, len, mu, sigma) {
    x = rep(NA, (len+1))
    
    if (length(start) > 1) start <- mean(start)
    x[1] = start
    
    for(i in 2:(len+1)){
        x[i] = x[i-1]*exp(mu)
    }
    return(x)
}

## Tests for BTC Diffusion Process ##
create_tests_results <- function(diffusion.table, rowname, mu, sigma) {
    
    diffusion.diff <- apply(log(diffusion.table), 2, diff)
    diffusion.SDs <- apply(diffusion.diff, 2, sd)
    diffusion.SDs.mean <- mean(diffusion.SDs)
    diffusion.SDs.sd <- sd(diffusion.SDs)
    
    diffusion.means <- apply(diffusion.diff, 2, mean)
    diffusion.means.mean <- mean(diffusion.means)
    diffusion.means.sd <- sd(diffusion.means)
    
    delta.sd <- mean(diffusion.SDs) - sigma
    delta.mu <- mean(diffusion.means) - (mu - sigma^2/2)
    
    x.vec = format_text(c(diffusion.SDs.mean, diffusion.SDs.sd, diffusion.means.mean, diffusion.means.sd, delta.sd, delta.mu), 4)
    
    x.matrix <- matrix(c(x.vec), nrow=1)
    colnames(x.matrix) <- c("Mean of SDs", "SD of SDs", "Mean of means", "SD of means", "SD test", "Mu test")
    rownames(x.matrix) <- rowname
    
    return(list(Table = x.matrix, MuVec = diffusion.means))
}

Then we will define functions to obtain the cash flow, NPV and an auxiliary function to select the grater results between two return series at each point.

## Project Cash Flow Functions ##

P_and_L <- function(revenue, variableCosts, fixedCost, taxesPerc, depreciation, taxOnRevenue) {
    if (taxOnRevenue) {
        PandL <- revenue*(1-taxesPerc)-variableCosts-fixedCost
    } else {
        PandL <- (revenue-variableCosts-fixedCost-depreciation)*(1-taxesPerc)+depreciation
    }
    return(PandL)
}

npv <- function(cf, r) {
    len <- length(cf)
    r.vec <- rep(NA, len)
    for (i in 1:len){
        r.vec[i] <- (1+r)^(i-1)
    }
    return(sum(cf / r.vec))
}

select_greater <- function(input1, input2) {
    # The best results from each scenario are chosen a posteriori 
    # This is a simplified version of the agents having an instant and more granular choice
    
    results <- input1
    index.vec <- which(input2 > input1)
    results[index.vec] <- input2[index.vec]
    return(results)
}

The next function is simply a mask to printing numbers onscreen with no decimal places and a thousands separator.

## Display results with comma separator and with a specific number of decimals

format_text <- function(text, decPlaces) { 
    format(round(as.numeric(text), decPlaces), nsmall=decPlaces, big.mark=",") 
}

And finally we create functions to return tables of results, and one histogram plotting function with many adjustable parameters.

## Auxiliary Functions ##

create_more_results_table <- function(NPV, rowname) {
    
    meanNPV = mean(NPV)
    meanNegNPV = mean(NPV[NPV < 0])
    meanPosNPV = mean(NPV[NPV > 0])
    
    nElements = round(length(NPV)*0.05,0)
    CVaRNPV = mean(sort(NPV)[1:nElements])
    VaRNPV =  sort(NPV)[nElements]
    
    lambda <- 0.5
    ECPNPV = (1-lambda)*meanNPV + lambda*CVaRNPV
    EqECPNPV = meanNPV + lambda/(1-lambda) * (CVaRNPV - VaRNPV)
    
    upsideIndex = meanPosNPV/abs(meanNegNPV)
    
    x.vec = format_text(c(meanNPV, CVaRNPV, ECPNPV, EqECPNPV), 0)
    x.vec = c(x.vec, format_text(upsideIndex, 2))
    x.vec = c(x.vec, format_text(c(meanNegNPV, meanPosNPV), 0))
        
    x.matrix <- matrix(x.vec, nrow=1)
    colnames(x.matrix) <- c("Mean of NPV", "CVaR at 95%", "ECP at 0.5", "Certainty Eq.", "Upside Potential", "Mean of -NPV", "Mean of +NPV")
    rownames(x.matrix) <- rowname
    
    return(x.matrix)
}

create_results_table <- function(NPV, rowname, BaseNPV = NULL) {
    
    meanNPV = mean(NPV)
    
    nNegNPV = sum(NPV < 0)
    nElements = length(NPV)
    PercNeg = nNegNPV/nElements
    
    if (!is.null(BaseNPV)) {
        compareMeans = meanNPV/mean(BaseNPV) - 1
        comparePerc = PercNeg - sum(BaseNPV < 0)/nElements
        compare.vec = format_text(c(compareMeans, comparePerc), 2) 
    } else {
        compare.vec = rep("-", 2)
    }
    
    x.vec = c(format_text(meanNPV, 0), format_text(PercNeg, 2))
    x.vec = c(x.vec, compare.vec)
        
    x.matrix <- matrix(x.vec, nrow=1)
    colnames(x.matrix) <- c("Mean of NPV", "Perc. Neg.", "NPV/Base", "Perc. - Base")
    rownames(x.matrix) <- rowname
    
    return(x.matrix)
}

create_results_hist <- function(NPV, breaksLen, plotXLim, textXAdj, textYAdj, subTextAdj, lineAdj, plotWidth, plotHeight) {
    options(repr.plot.width=plotWidth, repr.plot.height=plotHeight)
    
    NPV = NPV/1000000
    meanNPV = mean(NPV)
    minNPV = min(NPV)
    maxNPV = max(NPV)
    percNeg <- round(as.numeric(sum(NPV < 0)/length(NPV)*100), 0)
    
    breaks.vec <- seq(minNPV, maxNPV+breaksLen, by=breaksLen)
    
    quant95 <- quantile(NPV, 0.95)
    text.pos.x <- c(-textXAdj, quant95/2, quant95 + textXAdj)
    
    text.labels <- c(paste(percNeg, "%", sep=""), paste(95 - percNeg, "%", sep=""), "5%")
    text.labels <- paste("<", text.labels, ">")
    text.colors <- c("black", "red", "black")
    
    hist.obj <- hist(NPV, breaks=breaks.vec, border="darkred", col="red", xlab="NPV in Millions", main="", xlim=plotXLim, freq=FALSE)
    abline(v=c(0, quant95), lty=2)

    textYPos <- max(hist.obj$density) + textYAdj
    text(meanNPV, subTextAdj, labels=paste("| Mean:", round(meanNPV, 2)), adj=0, cex=0.8)
    text(quant95, subTextAdj, labels=paste(" Q95:", round(quant95, 2)), adj=0, cex=0.8)

    text(text.pos.x, textYPos, labels=text.labels, col=text.colors, cex=0.8)
    text(-textXAdj, textYPos - lineAdj, labels="Min:", cex=0.8)
    text(quant95+textXAdj, textYPos - lineAdj, labels="Max:", cex=0.8)
    text(-textXAdj, textYPos - 2 * lineAdj, labels=round(minNPV, 2), cex=0.8)
    text(quant95+textXAdj, textYPos - 2 * lineAdj, labels=round(maxNPV, 2), cex=0.8)
    
    return(hist.obj)
}

Local variables definition

Set data for Wind Power generation

# Based on (Lira and Moita Neto, 2017)
wind.velocity = c(2.3,2.6,2.4,2.1,2.1,2.95,3.5,3.6,3.8,3.1,3,2.5) 

# Given by the technology used
windToPower <- 1871.208247 

power.production <- wind.velocity * windToPower

## Chart ##
barplot(power.production, col="blue", xlab="Average Monthly Output", ylab="MWh", names.arg=month.abb, ylim=c(0,8000))

Constants for PLD Stochastic variable estimation

## PLD Data ##

# As defined by ONS + expected future increase adjustment
PLDMax <- 150 

# Defined in paper
PLDStart <- 75 
PLDEta <- 0.08038 
PLDRevertingMean <- 86.30
PLDVolatility <- 0.557

Constants for BTC Stochastic variable estimation, along with production costs and power consumption

## BTC Data ##

# Defined in paper
BTCMu <- -0.0366 
BTCSigma <- 0.2228

## BTC Mining Data ## 

# Antminer S17 Pro 
# Used to calculate consumption costs
BTCMinerHash <- 56*10^12 # Hashes per second
BTCMinerPower <- 2212 # Watts 
# Used to calculate investment
BTCMinerCost <- 1900 # USD

## BTC Stochastic Process

# Used if BTCStart is set to "regression"
BTCRegression <- 0.089497807 

# Used if BTCStart is set to "triangular"
BTCTriangle <- c(5000, 7000, 9000) 

# Used if BTCStart is set to "deterministic"
# as of 2019-11-19 
BTCInitialPrice <- 8105 

# Used for Deterministic and Triangular starts
# as of 2019-11-19
BTCInitialDifficulty <- 12720005267390.5 

Variables for cash flow and NPV

## Project Cash Flow Data ##

# BRL / USD exchange rate
BRLUSDEx <- 4 # R$/US$

# Constants for Wind Farm - based on (Fontanet, 2012)
InitialInvestment <- 9379943/BRLUSDEx 
FixedCosts <- 52757/BRLUSDEx 

# Defined in paper
VariableCosts <- 0.14 # % 
WACC <- 0.08 # Annual
RF <- 0.05 # Annual

# Refrigeration costs for BTC Mining in percentage of variable costs
Refrig <- 0.85 

# Simplified tax regime 
Taxes <- 0.25*0.08+0.09*0.12 

Stochastic processes

PLD Diffusion

## PLD Series ##

# Matrix of all series
PLD.matrix <- PLD_Diffusion(PLDStart, 72, NSeries, PLDRevertingMean, PLDVolatility, PLDEta, PLDMax)

# Means for each period from all simulations
PLD.period.means <- apply(PLD.matrix, 1, mean) 

# Vector of deterministic series
PLD.deterministic.series <- PLD_Deterministic(PLDStart, 72, PLDRevertingMean, PLDVolatility, PLDEta, PLDMax)

## Chart ##
matplot(1:73, cbind(PLD.matrix[, 1000], PLD.period.means, PLD.deterministic.series), type='l', xlab='Periods', ylab='series')
legend("top", inset=.02, legend=c("Random Series","MonteCarlo Mean","Deterministic Series"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n")

BTC Diffusion

## BTC Starting point ##

# BTC Consumption - used for Deterministic and Triangular Start Types
BTCConsumptionFactor <- (2^32*BTCMinerPower)/(BTCMinerHash*3600*12.5*1000) # kWh/BTC

# Set Start variable for Deterministic Type
BTCStartDeterministic <- BTCInitialPrice / (BTCConsumptionFactor * BTCInitialDifficulty)

# Set Start variable for Regression Type
BTCStartRegression <- BTCRegression / (BTCConsumptionFactor*10^8)

# Triangular distribution for BTC Start - if Triangular Type is selected
BTCStartTriangle <- rtriang(NSeries, BTCTriangle[1], BTCTriangle[3], BTCTriangle[2]) / (BTCConsumptionFactor * BTCInitialDifficulty)

# Choose BTCStart based on BTCStartType Global Variable
BTCStart <- switch(BTCStartType, "deterministic" = BTCStartDeterministic, "triangular" = BTCStartTriangle, "regression" = BTCStartRegression)

# If Triangular Type then plot distribution
if (BTCStartType == "triangular") hist(BTCStart, border="darkred", col="red", xlab="BTC Price/Difficulty Starting Point", main="", freq=FALSE)

## BTC Series and Charts ##

# Vector of BTC deterministic series for the first mining interval
BTC.1.deterministic.series <- c(rep(0, 22), BTC_Deterministic(BTCStart, 26, BTCMu, BTCSigma), rep(0, 24))

# Vector of BTC deterministic series for the final mining interval
BTC.2.deterministic.series <- c(rep(0, 22), BTC_Deterministic(BTCStart, 26, BTCMu, BTCSigma), BTC_Deterministic(BTCStart, 26, BTCMu, BTCSigma)[-(1:3)])

# Plot both deterministic series
plot(BTC.1.deterministic.series, type="l", xlab="Period", ylab="Price/Difficulty")

plot(BTC.2.deterministic.series, type="l", xlab="Period", ylab="Price/Difficulty")


# Create a matrix for stochastic series for the first mining interval
BTC.1.matrix <- BTC_Diffusion(BTCStart, 26, NSeries, BTCMu, BTCSigma)
BTC.1.matrix <- rbind(matrix(0, nrow=22, ncol=NSeries), BTC.1.matrix, matrix(0, nrow=24, ncol=NSeries))

# Obtain the average for each period
BTC.1.period.means <- apply(BTC.1.matrix, 1, mean)

# Plot one series of the stochastic matrix along the deterministic series and the vector of averages
matplot(1:73, cbind(BTC.1.matrix[, 2], BTC.1.period.means, BTC.1.deterministic.series), type='l', xlab='Periods', ylab='series')
legend("top", inset=.02, legend=c("Random Series","MonteCarlo Mean","Deterministic Series"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n")


# Create a matrix for stochastic series for the first mining interval
BTC.2.matrix <- BTC_Diffusion(BTCStart, 26, NSeries, BTCMu, BTCSigma)
BTC.2.matrix <- BTC.2.matrix[-c(1:3), ]
BTC.2.matrix <- rbind(BTC.1.matrix[1:49, ], BTC.2.matrix)

# Obtain the average for each period
BTC.2.period.means <- apply(BTC.2.matrix, 1, mean) 

# Plot one series of the stochastic matrix along the deterministic series and the vector of averages
matplot(1:73, cbind(BTC.2.matrix[, 2], BTC.2.period.means, BTC.2.deterministic.series), type='l', xlab='Periods', ylab='series')
legend("top", inset=.02, legend=c("Random Series","MonteCarlo Mean","Deterministic Series"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n")

Perform tests on the BTC diffusion process

This is used for debugging and can slow down calculations.

# Controled by Global Variable testBTCDiffusion
if (testBTCDiffusion) {
    test_results_1 <- create_tests_results(BTC.1.matrix[23:49, ], "BTC 1", BTCMu, BTCSigma)
    test_results_2 <- create_tests_results(BTC.2.matrix[50:73, ], "BTC 2", BTCMu, BTCSigma)
    
    rbind(test_results_1$Table, test_results_2$Table)
}

if (testBTCDiffusion) hist(test_results_1$MuVec, border="darkred", col="red", xlab="Mu BTC 1", main="", freq=FALSE)

if (testBTCDiffusion) hist(test_results_2$MuVec, border="darkred", col="red", xlab="Mu BTC 2", main="", freq=FALSE)

Revenue and Cash Flow Calculations

# Create a long vector of power production
production.series <- c(NA, rep(power.production, 6))

# Monetary results of producing energy and selling in PLD
PLD.output <- PLD.matrix[26:73, ] * production.series[26:73]

# Set BTC production cap
BTCMax <- (numberBTCMiners*BTCMinerPower/1000)/Refrig 

# Auxiliary variables for cap on BTC production
capped.production.series <- production.series
capped.production.series[production.series > BTCMax] <- BTCMax

# Monetary results of producing energy, generating BTC and selling in spot prices for the first interval
BTC.1.output <- BTC.1.matrix[26:49, ] * capped.production.series[26:49] * Refrig * 1000
BTC.1.output <- rbind(BTC.1.output, PLD.output[25:48, ])

# Monetary results of producing energy, generating BTC and selling in spot prices for the final interval
BTC.2.output <- BTC.2.matrix[26:73, ] * capped.production.series[26:73] * Refrig * 1000

# Electricity that has not been used for BTC mining due to production cap can be sold at PLD
# Adds extra output if TRUE
if (extraProduction) { 
  extra.production.series <- production.series - capped.production.series
  extra.output.2 <- PLD.matrix[26:73, ] * extra.production.series[26:73]
  extra.output.1 <- rbind(extra.output.2[1:24, ], matrix(0, nrow=24, ncol=NSeries))
  BTC.1.output <- BTC.1.output + extra.output.1
  BTC.2.output <- BTC.2.output + extra.output.2
}

Project Cash Flow - without investment costs

## Cash Flow Results ##

PLD.cashflow <- P_and_L(PLD.output, PLD.output*VariableCosts, FixedCosts, Taxes, 0 , TRUE)
PLD.cashflow <- rbind(matrix(0, nrow=25, ncol=ncol(PLD.cashflow)), PLD.cashflow)

BTC.1.cashflow <- P_and_L(BTC.1.output, PLD.output*VariableCosts, FixedCosts, Taxes, 0, TRUE)
BTC.1.cashflow <- rbind(matrix(0, nrow=25, ncol=ncol(BTC.1.cashflow)), BTC.1.cashflow)
BTC.1.cashflow <- select_greater(PLD.cashflow, BTC.1.cashflow)

BTC.2.cashflow <- P_and_L(BTC.2.output, PLD.output*VariableCosts, FixedCosts, Taxes, 0, TRUE)
BTC.2.cashflow <- rbind(matrix(0, nrow=25, ncol=ncol(BTC.2.cashflow)), BTC.2.cashflow)
BTC.2.cashflow <- select_greater(PLD.cashflow, BTC.2.cashflow)

PLD.mean.cashflow <- apply(PLD.cashflow, 1, mean)
BTC.1.mean.cashflow <- apply(BTC.1.cashflow, 1, mean)
BTC.2.mean.cashflow <- apply(BTC.2.cashflow, 1, mean)

Cashflow charts

# Select one specific series to be plotted
i = 4

matplot(1:73, cbind(PLD.cashflow[, i], BTC.1.cashflow[, i], BTC.2.cashflow[, i]), type='l', xlab='Periods', ylab='series')
legend("topleft", inset=.1, legend=c("PLD","BTC2","BTC2+2"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n", title=paste("MonteCarlo Series",i))

# Plot averages
matplot(1:73, cbind(PLD.mean.cashflow, BTC.1.mean.cashflow, BTC.2.mean.cashflow), type='l', xlab='Periods', ylab='series')
legend("topleft", inset=.08, legend=c("PLD","BTC2","BTC2+2"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n", title="MonteCarlo Averages")

Obtaining Deterministic Results for Debugging

PLD.output.series <- PLD.period.means * production.series
PLD.output.series[1:25] <- 0

BTC.1.output.series <- c(BTC.1.deterministic.series[1:49]*capped.production.series[1:49]*Refrig*1000, PLD.output.series[50:73])

BTC.2.output.series <- BTC.2.deterministic.series*capped.production.series*Refrig*1000

if(extraProduction) { # Adds extra output if TRUE
    extra.output.2 <- extra.production.series[26:73]*PLD.deterministic.series[26:73]
    extra.output.1 <- c(extra.output.2[1:24], rep(0, 24))
    BTC.1.output.series[26:73] <- BTC.1.output.series[26:73] + extra.output.1
    BTC.2.output.series[26:73] <- BTC.2.output.series[26:73] + extra.output.2
}

PLD.deterministic.cashflow <- PLD.output.series*(1-VariableCosts-Taxes)-FixedCosts

BTC.1.deterministic.cashflow <- BTC.1.output.series*(1-Taxes)-PLD.output.series*VariableCosts-FixedCosts

BTC.2.deterministic.cashflow <- BTC.2.output.series*(1-Taxes)-PLD.output.series*VariableCosts-FixedCosts

## Chart ##

matplot(1:73, cbind(PLD.deterministic.cashflow, BTC.1.deterministic.cashflow, BTC.2.deterministic.cashflow), type='l', xlab='Periods', ylab='series')
legend("topleft", inset=.08, legend=c("PLD","BTC2","BTC2+2"),col=c("black", "red", "green"), lty=1:3, cex=0.6, horiz=TRUE, bty="n", title="Deterministic Series")

Project NPV

## Project NPV for each scenario ##

# Calculate monthly rate
RFMonthly <- (1+RF)^(0.0833333333333333)-1
WACCMonthly <- (1+WACC)^(0.0833333333333333)-1

# Investment for BTC mining in both first and final interval
BTCInvestment.1 <- numberBTCMiners*BTCMinerCost*((1+RFMonthly)/(1+WACCMonthly))^22
BTCInvestment.2 <- numberBTCMiners*BTCMinerCost*((1+RFMonthly)/(1+WACCMonthly))^46

# Duplicate data set to allow for stage debugging - may cost memory
NPV.PLD.cashflow <- PLD.cashflow
# Insert investment in cash flow
NPV.PLD.cashflow[1, ] <- NPV.PLD.cashflow[1, ]-InitialInvestment
# Obtain NPV
NPV.PLD <- apply(NPV.PLD.cashflow, 2, npv, r=RFMonthly)

# Duplicate data set to allow for stage debugging - may cost memory
NPV.BTC.1.cashflow <- BTC.1.cashflow
# Insert investments in cash flow
NPV.BTC.1.cashflow[1, ] <- NPV.BTC.1.cashflow[1, ]-InitialInvestment
NPV.BTC.1.cashflow[23, ] <- NPV.BTC.1.cashflow[23, ]-BTCInvestment.1
# Obtain NPV
NPV.BTC.1 <- apply(NPV.BTC.1.cashflow, 2, npv, r=RFMonthly)

# Duplicate data set to allow for stage debugging - may cost memory
NPV.BTC.2.cashflow <- BTC.2.cashflow
# Insert investments in cash flow
NPV.BTC.2.cashflow[1, ] <- NPV.BTC.2.cashflow[1, ]-InitialInvestment
NPV.BTC.2.cashflow[23, ] <- NPV.BTC.2.cashflow[23, ]-BTCInvestment.1
NPV.BTC.2.cashflow[47, ] <- NPV.BTC.2.cashflow[47, ]-BTCInvestment.2
# Obtain NPV
NPV.BTC.2 <- apply(NPV.BTC.2.cashflow, 2, npv, r=RFMonthly)

NPV for mean results - used for debugging only

NPV.PLD.mean.cashflow <- PLD.mean.cashflow
NPV.PLD.mean.cashflow[1] <- -InitialInvestment

NPV.PLD.mean <- npv(NPV.PLD.mean.cashflow, r=RFMonthly)

NPV.BTC.1.mean.cashflow <- BTC.1.mean.cashflow
NPV.BTC.1.mean.cashflow[1] <- -InitialInvestment
NPV.BTC.1.mean.cashflow[23] <- BTC.1.mean.cashflow[23]-BTCInvestment.1

NPV.BTC.1.mean <- npv(NPV.BTC.1.mean.cashflow, r=RFMonthly)

NPV.BTC.2.mean.cashflow <- BTC.2.mean.cashflow
NPV.BTC.2.mean.cashflow[1] <- -InitialInvestment
NPV.BTC.2.mean.cashflow[23] <- BTC.2.mean.cashflow[23]-BTCInvestment.1
NPV.BTC.2.mean.cashflow[47] <- BTC.2.mean.cashflow[47]-BTCInvestment.2

NPV.BTC.2.mean <- npv(NPV.BTC.2.mean.cashflow, r=RFMonthly)

Third scenario not included in paper

choice.vector <- (NPV.PLD > NPV.BTC.1)

BTC.3.cashflow <- BTC.2.cashflow
BTC.3.cashflow[49:73, choice.vector] <- PLD.cashflow[49:73, choice.vector]

NPV.BTC.3.cashflow <- BTC.3.cashflow
NPV.BTC.3.cashflow[1, ] <- NPV.BTC.3.cashflow[1, ]-InitialInvestment
NPV.BTC.3.cashflow[23, ] <- NPV.BTC.3.cashflow[23, ]-BTCInvestment.1
NPV.BTC.3.cashflow[47, !choice.vector] <- NPV.BTC.3.cashflow[47, !choice.vector]-BTCInvestment.2

NPV.BTC.3 <- apply(NPV.BTC.3.cashflow, 2, npv, r=RFMonthly)

Displaying Results

Average results - for debugging purposes only

kable(cbind(
  "PLD"=format_text(mean(NPV.PLD.mean), 0), 
  "BTC_1"=format_text(mean(NPV.BTC.1.mean), 0), 
  "BTC_2"=format_text(mean(NPV.BTC.2.mean), 0)
), caption="NPV for MonteCarlo Averages")
NPV for MonteCarlo Averages
PLD BTC_1 BTC_2
1,510,804 3,630,675 5,749,476

Base Scenario Results

results.matrix.PLD = create_results_table(NPV.PLD, "Base")
more.results.matrix.PLD = create_more_results_table(NPV.PLD, "Base")

kable(results.matrix.PLD)
Mean of NPV Perc. Neg. NPV/Base Perc. - Base
Base 1,510,804 0.38 - -

## Chart ##

if (savePDF) pdf(file="./Plots/Base.pdf", width=8, height=5)

PLD.hist <- create_results_hist(NPV.PLD, 0.625, c(-10,30), 3.5, 0.002, -0.0036, 0.008, 8, 6)


if (savePDF) dev.off()

First Scenario Results

results.matrix.BTC.1 = create_results_table(NPV.BTC.1, "2 Years", NPV.PLD)
more.results.matrix.BTC.1 = create_more_results_table(NPV.BTC.1, "2 Years")

kable(results.matrix.BTC.1)
Mean of NPV Perc. Neg. NPV/Base Perc. - Base
2 Years 3,630,675 0.24 1.40 -0.14
## Chart ##

if (savePDF) pdf(file="./Plots/2+0_Scenario.pdf", width=8, height=5)

BTC.1.hist <- create_results_hist(NPV.BTC.1, 0.625, c(-10,30), 3.5, 0.002, -0.0022, 0.004, 8, 6)


if (savePDF) dev.off()

Second Scenario Results

results.matrix.BTC.2 = create_results_table(NPV.BTC.2, "2+2 Years", NPV.PLD)
more.results.matrix.BTC.2 = create_more_results_table(NPV.BTC.2, "2+2 Years")

kable(results.matrix.BTC.2)
Mean of NPV Perc. Neg. NPV/Base Perc. - Base
2+2 Years 5,749,476 0.15 2.81 -0.23

## Chart ##

if (savePDF) pdf(file="./Plots/2+2_Scenario.pdf", width=8, height=5)

BTC.2.hist <- create_results_hist(NPV.BTC.2, 0.625, c(-10,30), 3.5, 0.002, -0.0017, 0.004, 8, 6)


if (savePDF) dev.off()

Third Scenario Results - not included in paper

ChoiceScenarios <- NSeries - sum(choice.vector)
PercChoice <- ChoiceScenarios/NSeries*100


results.matrix.BTC.3 = create_results_table(NPV.BTC.3, "2 or 4 Years", NPV.PLD)
more.results.matrix.BTC.3 = create_more_results_table(NPV.BTC.3, "2 or 4 Years")

kable(results.matrix.BTC.3, caption=paste("Scenarios with Choice:", ChoiceScenarios, "out of", NSeries, "(", PercChoice, "%)"))
Scenarios with Choice: 29582 out of 50000 ( 59.164 %)
Mean of NPV Perc. Neg. NPV/Base Perc. - Base
2 or 4 Years 4,967,531 0.21 2.29 -0.16
## Chart ##

if (savePDF) pdf(file="./Plots/2+2_Scenario+Choice.pdf", width=8, height=5)

BTC.3.hist <- create_results_hist(NPV.BTC.3, 0.625, c(-10,30), 3.5, 0.002, -0.0017, 0.004, 8, 6)


if (savePDF) dev.off()

Aggregated Results

kable(rbind(more.results.matrix.PLD, more.results.matrix.BTC.1, more.results.matrix.BTC.3, more.results.matrix.BTC.2), caption="Table of Extra Information")
Table of Extra Information
Mean of NPV CVaR at 95% ECP at 0.5 Certainty Eq. Upside Potential Mean of -NPV Mean of +NPV
Base 1,510,804 -2,201,377 -345,287 1,261,748 2.75 -1,127,823 3,102,644
2 Years 3,630,675 -2,811,906 409,384 3,006,405 3.76 -1,378,741 5,185,130
2 or 4 Years 4,967,531 -2,849,382 1,059,075 4,359,782 4.52 -1,486,646 6,714,341
2+2 Years 5,749,476 -2,778,596 1,485,440 4,788,105 4.77 -1,474,459 7,032,695
kable(rbind(results.matrix.PLD, results.matrix.BTC.1, results.matrix.BTC.3, results.matrix.BTC.2), caption="Table of Results")
Table of Results
Mean of NPV Perc. Neg. NPV/Base Perc. - Base
Base 1,510,804 0.38 - -
2 Years 3,630,675 0.24 1.40 -0.14
2 or 4 Years 4,967,531 0.21 2.29 -0.16
2+2 Years 5,749,476 0.15 2.81 -0.23
LS0tDQp0aXRsZTogIk1vbnRlIENhcmxvIFNpbXVsYXRpb24iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyAgSGVkZ2luZyBSZW5ld2FibGUgRW5lcmd5IEludmVzdG1lbnRzIHdpdGggQml0Y29pbiBNaW5pbmcNCg0KQXV0aG9yczogQmFzdGlhbi1QaW50bywgQy4sIEFyYXVqbywgRi4gVmRTLiwgQnJhbmTDo28sIEwuIEUuIFQuLCBHb21lcywgTC4gTC4NCg0KQWJzdHJhY3QgUmVuZXdhYmxlIGVuZXJneSBzb3VyY2VzIHN1Y2ggYXMgd2luZCBwb3dlciBhcmUgaW5jcmVhc2luZyB0aGVpciBzaGFyZSBvZiB0aGUgd29ybGQgZW5lcmd5IG1hdHJpeC4gTm9uZXRoZWxlc3MsIHdpbmQgZmFybXMgcHJvamVjdHMgYXJlIHN1YmplY3QgdG8gdmFyaWF0aW9ucyBpbiBvdXRwdXQgZHVlIHRvIGNsaW1hdGUgY29uZGl0aW9ucyBhbmQgdG8gcHJpY2Ugdm9sYXRpbGl0eSBpZiB0aGV5IGNob29zZSB0byBhbnRpY2lwYXRlIGNvbnN0cnVjdGlvbiB0byBzZWxsIHRoZWlyIGVuZXJneSBpbiB0aGUgc2hvcnQgdGVybSBtYXJrZXRzLiBJbiBvcmRlciB0byBjcmVhdGUgaW5jZW50aXZlcyBmb3IgZWFybHkgaW52ZXN0bWVudCwgd2Ugc2hvdyB0aGF0IHdpbmQgZmFybSBpbnZlc3RvcnMgY2FuIGhlZGdlIGVsZWN0cmljaXR5IHByaWNlIHJpc2sgYnkgc2ltdWx0YW5lb3VzbHkgaW52ZXN0aW5nIGluIGEgY3J5cHRvY3VycmVuY3kgbWluaW5nIGZhY2lsaXR5IHRoYXQgdXNlcyBlbGVjdHJpY2l0eSBhcyBpbnB1dCB0byBwcm9kdWNlIG5ld2x5IG1pbnRlZCBCaXRjb2lucyB0byBzZWxsIGluIHRoZSBtYXJrZXQuIEdpdmVuIHRoYXQgZWxlY3RyaWNpdHkgYW5kIEJpdGNvaW4gcHJpY2VzIGFyZSBtb3N0bHkgdW5jb3JyZWxhdGVkLCB0aGUgYWJpbGl0eSB0byBzd2l0Y2ggb3V0cHV0cyBiZXR3ZWVuIHRoZXNlIHR3byBhc3NldHMgZGVwZW5kaW5nIG9uIHRoZWlyIHJlbGF0aXZlIHByaWNlcywgYWxsb3dzIHRoZSBmaXJtIHRvIG1heGltaXplIHJldmVudWVzIGFuZCBtaW5pbWl6ZSBsb3NzZXMuIFdlIGRldmVsb3AgYSBudW1lcmljYWwgYXBwbGljYXRpb24gd2hlcmUgd2UgYXBwbHkgdGhlIHJlYWwgb3B0aW9ucyBhcHByb2FjaCB0byBtb2RlbCBhIHdpbmQgZmFybSB0aGF0IGNob29zZXMgdG8gYW50aWNpcGF0ZSBjb25zdHJ1Y3Rpb24gaW4gb3JkZXIgdG8gc2VsbCBlbmVyZ3kgaW4gdGhlIHNob3J0IHRlcm0gbWFya2V0IGZvciB1cCB0byBmb3VyIHllYXJzIHByaW9yIHRvIGVudGVyaW5nIGludG8gaXRzIGxvbmcgdGVybSBlbmVyZ3kgc2FsZXMgY29tbWl0bWVudC4gR2l2ZW4gdGhhdCB0aGlzIHBvd2VyIHBsYW50IGFsc28gaW52ZXN0cyBpbiBhIEJpdGNvaW4gbWluaW5nIGZhY2lsaXR5LCB3aGVuZXZlciB0aGUgcHJpY2Ugb2YgdGhlIEJpdGNvaW5zIGNyZWF0ZWQgaXMgaGlnaGVyIHRoYW4gdGhlIG1hcmtldCBwcmljZSBvZiBlbGVjdHJpYyBwb3dlciwgdGhlIGZpcm0gd2lsbCBjaG9vc2UgdG8gb3BlcmF0ZSB0aGUgbWluaW5nIGZhY2lsaXR5LiBPdGhlcndpc2UsIGl0IHdpbGwgc2VsbCBpdHMgZW5lcmd5IHRvIHRoZSBtYXJrZXQuIFRoZSBzaG9ydC10ZXJtIGVuZXJneSBwcmljZSBhbmQgQml0Y29pbiBwcmljZS9taW5pbmctZGlmZmljdWx0eSByYXRpbyBhcmUgbW9kZWxlZCBhcyB0d28gZGlzdGluY3Qgc3RvY2hhc3RpYyBkaWZmdXNpb24gcHJvY2Vzc2VzLiBUaGUgcmVzdWx0cyBzaG93IHRoYXQgdGhlIG9wdGlvbiB0byBzd2l0Y2ggb3V0cHV0cyBzaWduaWZpY2FudGx5IGluY3JlYXNlcyB0aGUgZ2VuZXJhdG9y4oCZcyByZXZlbnVlIHdoaWxlIHNpbXVsdGFuZW91c2x5IGRlY3JlYXNpbmcgdGhlIHJpc2suDQoNCktleXdvcmRzOiByZWFsIG9wdGlvbnMsIHN3aXRjaCBvcHRpb24sIHJlbmV3YWJsZSBlbmVyZ3kgcHJvZHVjdGlvbiwgY3J5cHRvY3VycmVuY3kgbWluaW5nLCBiaXQtc3ByZWFkDQoNClRoaXMgd29yayBwcmVzZW50cyB0aGUgY2FsY3VsYXRpb25zIGRvbmUgZm9yIHRoZSBhcnRpY2xlIHJlZmVyZW5jZWQgYWJvdmUuIFRoZSBmb2xsb3dpbmcgY2FsY3VsYXRpb25zIHVzZSBwYXJhbWV0ZXJzIGZvciB0aGUgZGlmZnVzaW9uIG9mIHN0b2NoYXN0aWMgdmFyaWFibGVzIHRoYXQgaGF2ZSBiZWVuIGRlZmluZWQgaW4gdGhlIHBhcGVyLiBBbGwgdGhlIGNvZGUgd2FzIHJ1biBpbiBSU3R1ZGlvIHVzaW5nIHRoZSB2ZXJzaW9uIG9mIHRoZSBzb2Z0d2FyZSBiZWxvdy4NCg0KIyMjIFNvZnR3YXJlIHZlcnNpb24NCg0KYGBge3J9DQpSLnZlcnNpb24NCmBgYA0KDQojIyMgU2V0dGluZyBvZiB0aGUgZW52aXJvbm1lbnQNCg0KYGBge3J9DQojIFNldHMgdGhlIG51bWJlciBvZiBzZXJpZXMgdXNlZCBpbiB0aGUgTW9udGVDYXJsbyBTaW11bGF0aW9uDQpOU2VyaWVzIDwtIDUwMDAwIA0KDQojIFVzZWQgdG8gc2V0IEJUQyBwcm9kdWN0aW9uIGNhcCBhbmQgY2FsY3VsYXRlIGludmVzdG1lbnQNCm51bWJlckJUQ01pbmVycyA8LSAxNzUwIA0KDQojIFVzZWQgdG8gZGV0ZXJtaW5lIHRoZSBzdGFydGluZyB2YWx1ZSBvZiBCVEMgZGlmZnVzaW9uIHByb2Nlc3MNCiMgUG9zc2libGUgdmFsdWVzOiAiZGV0ZXJtaW5pc3RpYyIsICJ0cmlhbmd1bGFyIiwgInJlZ3Jlc3Npb24iDQojIEZpbmUgdHVuaW5nIGNhbiBiZSBkb25lIGluIHRoZSBCVENTdGFydCBzZWN0aW9uOyBvdmVycmlkZW4gaWYgZXhjZWxWZXJzaW9uID0gVFJVRQ0KQlRDU3RhcnRUeXBlIDwtICJ0cmlhbmd1bGFyIiANCg0KIyBTZXQgVFJVRSB0byBzZWxsIGV4Y2VkZW50IG9mIHBvd2VyIHByb2R1Y3Rpb24gYXQgUExEIHByaWNlcw0KIyBBbHdheXMgRkFMU0UgaWYgZXhjZWxWZXJzaW9uIGlzIFRSVUUNCmV4dHJhUHJvZHVjdGlvbiA8LSBUUlVFIA0KDQojIE1lYXN1cmUgbXUgYW5kIHNpZ21hIG9mIEJUQyBkaWZmdXNpb25zIHN0YXRpc3RpY3MNCiMgQ2FuIHNsb3cgZG93biBjYWxjdWxhdGlvbnMNCnRlc3RCVENEaWZmdXNpb24gPC0gRkFMU0UgDQoNCiMgU2V0IFRSVUUgdG8gc2F2ZSBoaXN0b2dyYW1zIGluIFBERiBmb3JtYXQNCiMgU2VlIGFsc28gb3RoZXIgdmFyaWFibGVzIHRvIGJlIHNldCBhdCB0aGUgY2hhcnQgZ2VuZXJhdGlvbiBjb21tYW5kIGxpbmUNCnNhdmVQREYgPC0gRkFMU0UgDQoNCiMgR2xvYmFsIENoYXJ0IENvbmZpZ3VyYXRpb25zDQojIFVzZWQgdG8gcmVzaXplIHBsb3RzDQpyZXF1aXJlKHJlcHIpIA0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGg9OCwgcmVwci5wbG90LmhlaWdodD0zKSANCiMgVXNlZCBmb3IgdHJpYW5ndWxhciBkaXN0cmlidXRpb24gd2hlbiBkZWZpbmVkIGJ5IEJUQ1N0YXJ0VHlwZQ0KcmVxdWlyZShleHRyYURpc3RyKQ0KIyBVc2VkIHRvIHByaW50IHRhYmxlcyBpbnNpZGUgdGhlIFIgTm90ZWJvb2sNCnJlcXVpcmUoa25pdHIpDQpgYGANCg0KDQojIyMgTG9jYWwgZnVuY3Rpb25zIGRlZmluaXRpb24NCg0KVGhlIGZpcnN0IHNldCBvZiBsb2NhbCBmdW5jdGlvbnMgYXJlIHVzZWQgdG8gY3JlYXRlIHRoZSBkaWZmdXNpb24gb2YgdGhlIHN0b2NoYXN0aWMgdmFyaWFibGVzIGFuZCB0aGVpciBkZXRlcm1pbmlzdGljIGNvdW50ZXJwYXJ0cy4NCg0KYGBge3J9DQojIyBEaWZmdXNpb24gRnVuY3Rpb25zICMjDQoNClBMRF9EaWZmdXNpb24gPC0gZnVuY3Rpb24oc3RhcnQsIGxlbiwgbiwgUmV2ZXJ0aW5nTWVhbiwgVm9sYXRpbGl0eSwgRXRhLCBNYXgpIHsNCiAgICAjIERpZmZ1c2lvbjEgPC0gUmV2ZXJ0aW5nTWVhbipleHAoLVZvbGF0aWxpdHleMi8oNCpFdGEpKQ0KICAgIERpZmZ1c2lvbjIgPC0gZXhwKC1FdGEpDQogICAgRGlmZnVzaW9uMyA8LSAobG9nKFJldmVydGluZ01lYW4pLVZvbGF0aWxpdHleMi8oMipFdGEpKSooMS1EaWZmdXNpb24yKQ0KICAgIERpZmZ1c2lvbjQgPC0gVm9sYXRpbGl0eSpzcXJ0KCgxLURpZmZ1c2lvbjJeMikvKDIqRXRhKSkNCiAgICANCiAgICB4ID0gbWF0cml4KE5BLCBucm93PShsZW4rMSksIG5jb2w9bikNCiAgICB4WzEsIF0gPSBzdGFydA0KICAgIA0KICAgIGZvcihpIGluIDI6KGxlbisxKSl7DQogICAgICAgIHhbaSwgXSA9IGV4cChsb2coeFtpLTEsIF0pKkRpZmZ1c2lvbjIrRGlmZnVzaW9uMytEaWZmdXNpb240KnJub3JtKG4sMCwxKSkNCiAgICAgICAgeFtpLCB4W2ksIF0gPiBNYXhdID0gTWF4DQogICAgfQ0KICAgIHJldHVybih4KQ0KfQ0KDQpQTERfRGV0ZXJtaW5pc3RpYyA8LSBmdW5jdGlvbihzdGFydCwgbGVuLCBSZXZlcnRpbmdNZWFuLCBWb2xhdGlsaXR5LCBFdGEsIE1heCkgew0KICAgIERpZmZ1c2lvbjEgPC0gbG9nKFJldmVydGluZ01lYW4pLVZvbGF0aWxpdHleMi8oMipFdGEpDQogICAgRGlmZnVzaW9uMiA8LSBWb2xhdGlsaXR5XjIvKDQqRXRhKQ0KICAgIA0KICAgIHggPSByZXAoTkEsIGxlbikNCiAgICANCiAgICBmb3IoaSBpbiAxOmxlbil7DQogICAgICAgIHhbaV0gPSBtaW4oTWF4LCBleHAobG9nKHN0YXJ0KSpleHAoLUV0YSppKStEaWZmdXNpb24xKigxLWV4cCgtRXRhKmkpKStEaWZmdXNpb24yKigxLWV4cCgtMipFdGEqaSkpKSkNCiAgICB9DQogICAgcmV0dXJuKGMoc3RhcnQsIHgpKQ0KfQ0KDQpCVENfRGlmZnVzaW9uIDwtIGZ1bmN0aW9uKHN0YXJ0LCBsZW4sIG4sIG11LCBzaWdtYSkgew0KICAgIHggPSBtYXRyaXgoTkEsIG5yb3c9KGxlbisxKSwgbmNvbD1uKQ0KICAgIHhbMSwgXSA9IHN0YXJ0DQogICAgDQogICAgZm9yKGkgaW4gMjoobGVuKzEpKXsNCiAgICAgICAgeFtpLCBdID0geFtpLTEsIF0qZXhwKHJub3JtKG4sIG11LXNpZ21hXjIvMiwgc2lnbWEpKQ0KICAgIH0NCiAgICByZXR1cm4oeCkNCn0NCg0KQlRDX0RldGVybWluaXN0aWMgPC0gZnVuY3Rpb24oc3RhcnQsIGxlbiwgbXUsIHNpZ21hKSB7DQogICAgeCA9IHJlcChOQSwgKGxlbisxKSkNCiAgICANCiAgICBpZiAobGVuZ3RoKHN0YXJ0KSA+IDEpIHN0YXJ0IDwtIG1lYW4oc3RhcnQpDQogICAgeFsxXSA9IHN0YXJ0DQogICAgDQogICAgZm9yKGkgaW4gMjoobGVuKzEpKXsNCiAgICAgICAgeFtpXSA9IHhbaS0xXSpleHAobXUpDQogICAgfQ0KICAgIHJldHVybih4KQ0KfQ0KDQojIyBUZXN0cyBmb3IgQlRDIERpZmZ1c2lvbiBQcm9jZXNzICMjDQpjcmVhdGVfdGVzdHNfcmVzdWx0cyA8LSBmdW5jdGlvbihkaWZmdXNpb24udGFibGUsIHJvd25hbWUsIG11LCBzaWdtYSkgew0KICAgIA0KICAgIGRpZmZ1c2lvbi5kaWZmIDwtIGFwcGx5KGxvZyhkaWZmdXNpb24udGFibGUpLCAyLCBkaWZmKQ0KICAgIGRpZmZ1c2lvbi5TRHMgPC0gYXBwbHkoZGlmZnVzaW9uLmRpZmYsIDIsIHNkKQ0KICAgIGRpZmZ1c2lvbi5TRHMubWVhbiA8LSBtZWFuKGRpZmZ1c2lvbi5TRHMpDQogICAgZGlmZnVzaW9uLlNEcy5zZCA8LSBzZChkaWZmdXNpb24uU0RzKQ0KICAgIA0KICAgIGRpZmZ1c2lvbi5tZWFucyA8LSBhcHBseShkaWZmdXNpb24uZGlmZiwgMiwgbWVhbikNCiAgICBkaWZmdXNpb24ubWVhbnMubWVhbiA8LSBtZWFuKGRpZmZ1c2lvbi5tZWFucykNCiAgICBkaWZmdXNpb24ubWVhbnMuc2QgPC0gc2QoZGlmZnVzaW9uLm1lYW5zKQ0KICAgIA0KICAgIGRlbHRhLnNkIDwtIG1lYW4oZGlmZnVzaW9uLlNEcykgLSBzaWdtYQ0KICAgIGRlbHRhLm11IDwtIG1lYW4oZGlmZnVzaW9uLm1lYW5zKSAtIChtdSAtIHNpZ21hXjIvMikNCiAgICANCiAgICB4LnZlYyA9IGZvcm1hdF90ZXh0KGMoZGlmZnVzaW9uLlNEcy5tZWFuLCBkaWZmdXNpb24uU0RzLnNkLCBkaWZmdXNpb24ubWVhbnMubWVhbiwgZGlmZnVzaW9uLm1lYW5zLnNkLCBkZWx0YS5zZCwgZGVsdGEubXUpLCA0KQ0KICAgIA0KICAgIHgubWF0cml4IDwtIG1hdHJpeChjKHgudmVjKSwgbnJvdz0xKQ0KICAgIGNvbG5hbWVzKHgubWF0cml4KSA8LSBjKCJNZWFuIG9mIFNEcyIsICJTRCBvZiBTRHMiLCAiTWVhbiBvZiBtZWFucyIsICJTRCBvZiBtZWFucyIsICJTRCB0ZXN0IiwgIk11IHRlc3QiKQ0KICAgIHJvd25hbWVzKHgubWF0cml4KSA8LSByb3duYW1lDQogICAgDQogICAgcmV0dXJuKGxpc3QoVGFibGUgPSB4Lm1hdHJpeCwgTXVWZWMgPSBkaWZmdXNpb24ubWVhbnMpKQ0KfQ0KYGBgDQoNClRoZW4gd2Ugd2lsbCBkZWZpbmUgZnVuY3Rpb25zIHRvIG9idGFpbiB0aGUgY2FzaCBmbG93LCBOUFYgYW5kIGFuIGF1eGlsaWFyeSBmdW5jdGlvbiB0byBzZWxlY3QgdGhlIGdyYXRlciByZXN1bHRzIGJldHdlZW4gdHdvIHJldHVybiBzZXJpZXMgYXQgZWFjaCBwb2ludC4NCg0KYGBge3J9DQojIyBQcm9qZWN0IENhc2ggRmxvdyBGdW5jdGlvbnMgIyMNCg0KUF9hbmRfTCA8LSBmdW5jdGlvbihyZXZlbnVlLCB2YXJpYWJsZUNvc3RzLCBmaXhlZENvc3QsIHRheGVzUGVyYywgZGVwcmVjaWF0aW9uLCB0YXhPblJldmVudWUpIHsNCiAgICBpZiAodGF4T25SZXZlbnVlKSB7DQogICAgICAgIFBhbmRMIDwtIHJldmVudWUqKDEtdGF4ZXNQZXJjKS12YXJpYWJsZUNvc3RzLWZpeGVkQ29zdA0KICAgIH0gZWxzZSB7DQogICAgICAgIFBhbmRMIDwtIChyZXZlbnVlLXZhcmlhYmxlQ29zdHMtZml4ZWRDb3N0LWRlcHJlY2lhdGlvbikqKDEtdGF4ZXNQZXJjKStkZXByZWNpYXRpb24NCiAgICB9DQogICAgcmV0dXJuKFBhbmRMKQ0KfQ0KDQpucHYgPC0gZnVuY3Rpb24oY2YsIHIpIHsNCiAgICBsZW4gPC0gbGVuZ3RoKGNmKQ0KICAgIHIudmVjIDwtIHJlcChOQSwgbGVuKQ0KICAgIGZvciAoaSBpbiAxOmxlbil7DQogICAgICAgIHIudmVjW2ldIDwtICgxK3IpXihpLTEpDQogICAgfQ0KICAgIHJldHVybihzdW0oY2YgLyByLnZlYykpDQp9DQoNCnNlbGVjdF9ncmVhdGVyIDwtIGZ1bmN0aW9uKGlucHV0MSwgaW5wdXQyKSB7DQogICAgIyBUaGUgYmVzdCByZXN1bHRzIGZyb20gZWFjaCBzY2VuYXJpbyBhcmUgY2hvc2VuIGEgcG9zdGVyaW9yaSANCiAgICAjIFRoaXMgaXMgYSBzaW1wbGlmaWVkIHZlcnNpb24gb2YgdGhlIGFnZW50cyBoYXZpbmcgYW4gaW5zdGFudCBhbmQgbW9yZSBncmFudWxhciBjaG9pY2UNCiAgICANCiAgICByZXN1bHRzIDwtIGlucHV0MQ0KICAgIGluZGV4LnZlYyA8LSB3aGljaChpbnB1dDIgPiBpbnB1dDEpDQogICAgcmVzdWx0c1tpbmRleC52ZWNdIDwtIGlucHV0MltpbmRleC52ZWNdDQogICAgcmV0dXJuKHJlc3VsdHMpDQp9DQpgYGANCg0KVGhlIG5leHQgZnVuY3Rpb24gaXMgc2ltcGx5IGEgbWFzayB0byBwcmludGluZyBudW1iZXJzIG9uc2NyZWVuIHdpdGggbm8gZGVjaW1hbCBwbGFjZXMgYW5kIGEgdGhvdXNhbmRzIHNlcGFyYXRvci4NCg0KYGBge3J9DQojIyBEaXNwbGF5IHJlc3VsdHMgd2l0aCBjb21tYSBzZXBhcmF0b3IgYW5kIHdpdGggYSBzcGVjaWZpYyBudW1iZXIgb2YgZGVjaW1hbHMNCg0KZm9ybWF0X3RleHQgPC0gZnVuY3Rpb24odGV4dCwgZGVjUGxhY2VzKSB7IA0KICAgIGZvcm1hdChyb3VuZChhcy5udW1lcmljKHRleHQpLCBkZWNQbGFjZXMpLCBuc21hbGw9ZGVjUGxhY2VzLCBiaWcubWFyaz0iLCIpIA0KfQ0KYGBgDQoNCkFuZCBmaW5hbGx5IHdlIGNyZWF0ZSBmdW5jdGlvbnMgdG8gcmV0dXJuIHRhYmxlcyBvZiByZXN1bHRzLCBhbmQgb25lIGhpc3RvZ3JhbSBwbG90dGluZyBmdW5jdGlvbiB3aXRoIG1hbnkgYWRqdXN0YWJsZSBwYXJhbWV0ZXJzLg0KDQpgYGB7cn0NCiMjIEF1eGlsaWFyeSBGdW5jdGlvbnMgIyMNCg0KY3JlYXRlX21vcmVfcmVzdWx0c190YWJsZSA8LSBmdW5jdGlvbihOUFYsIHJvd25hbWUpIHsNCiAgICANCiAgICBtZWFuTlBWID0gbWVhbihOUFYpDQogICAgbWVhbk5lZ05QViA9IG1lYW4oTlBWW05QViA8IDBdKQ0KICAgIG1lYW5Qb3NOUFYgPSBtZWFuKE5QVltOUFYgPiAwXSkNCiAgICANCiAgICBuRWxlbWVudHMgPSByb3VuZChsZW5ndGgoTlBWKSowLjA1LDApDQogICAgQ1ZhUk5QViA9IG1lYW4oc29ydChOUFYpWzE6bkVsZW1lbnRzXSkNCiAgICBWYVJOUFYgPSAgc29ydChOUFYpW25FbGVtZW50c10NCiAgICANCiAgICBsYW1iZGEgPC0gMC41DQogICAgRUNQTlBWID0gKDEtbGFtYmRhKSptZWFuTlBWICsgbGFtYmRhKkNWYVJOUFYNCiAgICBFcUVDUE5QViA9IG1lYW5OUFYgKyBsYW1iZGEvKDEtbGFtYmRhKSAqIChDVmFSTlBWIC0gVmFSTlBWKQ0KICAgIA0KICAgIHVwc2lkZUluZGV4ID0gbWVhblBvc05QVi9hYnMobWVhbk5lZ05QVikNCiAgICANCiAgICB4LnZlYyA9IGZvcm1hdF90ZXh0KGMobWVhbk5QViwgQ1ZhUk5QViwgRUNQTlBWLCBFcUVDUE5QViksIDApDQogICAgeC52ZWMgPSBjKHgudmVjLCBmb3JtYXRfdGV4dCh1cHNpZGVJbmRleCwgMikpDQogICAgeC52ZWMgPSBjKHgudmVjLCBmb3JtYXRfdGV4dChjKG1lYW5OZWdOUFYsIG1lYW5Qb3NOUFYpLCAwKSkNCiAgICAgICAgDQogICAgeC5tYXRyaXggPC0gbWF0cml4KHgudmVjLCBucm93PTEpDQogICAgY29sbmFtZXMoeC5tYXRyaXgpIDwtIGMoIk1lYW4gb2YgTlBWIiwgIkNWYVIgYXQgOTUlIiwgIkVDUCBhdCAwLjUiLCAiQ2VydGFpbnR5IEVxLiIsICJVcHNpZGUgUG90ZW50aWFsIiwgIk1lYW4gb2YgLU5QViIsICJNZWFuIG9mICtOUFYiKQ0KICAgIHJvd25hbWVzKHgubWF0cml4KSA8LSByb3duYW1lDQogICAgDQogICAgcmV0dXJuKHgubWF0cml4KQ0KfQ0KDQpjcmVhdGVfcmVzdWx0c190YWJsZSA8LSBmdW5jdGlvbihOUFYsIHJvd25hbWUsIEJhc2VOUFYgPSBOVUxMKSB7DQogICAgDQogICAgbWVhbk5QViA9IG1lYW4oTlBWKQ0KICAgIA0KICAgIG5OZWdOUFYgPSBzdW0oTlBWIDwgMCkNCiAgICBuRWxlbWVudHMgPSBsZW5ndGgoTlBWKQ0KICAgIFBlcmNOZWcgPSBuTmVnTlBWL25FbGVtZW50cw0KICAgIA0KICAgIGlmICghaXMubnVsbChCYXNlTlBWKSkgew0KICAgICAgICBjb21wYXJlTWVhbnMgPSBtZWFuTlBWL21lYW4oQmFzZU5QVikgLSAxDQogICAgICAgIGNvbXBhcmVQZXJjID0gUGVyY05lZyAtIHN1bShCYXNlTlBWIDwgMCkvbkVsZW1lbnRzDQogICAgICAgIGNvbXBhcmUudmVjID0gZm9ybWF0X3RleHQoYyhjb21wYXJlTWVhbnMsIGNvbXBhcmVQZXJjKSwgMikgDQogICAgfSBlbHNlIHsNCiAgICAgICAgY29tcGFyZS52ZWMgPSByZXAoIi0iLCAyKQ0KICAgIH0NCiAgICANCiAgICB4LnZlYyA9IGMoZm9ybWF0X3RleHQobWVhbk5QViwgMCksIGZvcm1hdF90ZXh0KFBlcmNOZWcsIDIpKQ0KICAgIHgudmVjID0gYyh4LnZlYywgY29tcGFyZS52ZWMpDQogICAgICAgIA0KICAgIHgubWF0cml4IDwtIG1hdHJpeCh4LnZlYywgbnJvdz0xKQ0KICAgIGNvbG5hbWVzKHgubWF0cml4KSA8LSBjKCJNZWFuIG9mIE5QViIsICJQZXJjLiBOZWcuIiwgIk5QVi9CYXNlIiwgIlBlcmMuIC0gQmFzZSIpDQogICAgcm93bmFtZXMoeC5tYXRyaXgpIDwtIHJvd25hbWUNCiAgICANCiAgICByZXR1cm4oeC5tYXRyaXgpDQp9DQoNCmNyZWF0ZV9yZXN1bHRzX2hpc3QgPC0gZnVuY3Rpb24oTlBWLCBicmVha3NMZW4sIHBsb3RYTGltLCB0ZXh0WEFkaiwgdGV4dFlBZGosIHN1YlRleHRBZGosIGxpbmVBZGosIHBsb3RXaWR0aCwgcGxvdEhlaWdodCkgew0KICAgIG9wdGlvbnMocmVwci5wbG90LndpZHRoPXBsb3RXaWR0aCwgcmVwci5wbG90LmhlaWdodD1wbG90SGVpZ2h0KQ0KICAgIA0KICAgIE5QViA9IE5QVi8xMDAwMDAwDQogICAgbWVhbk5QViA9IG1lYW4oTlBWKQ0KICAgIG1pbk5QViA9IG1pbihOUFYpDQogICAgbWF4TlBWID0gbWF4KE5QVikNCiAgICBwZXJjTmVnIDwtIHJvdW5kKGFzLm51bWVyaWMoc3VtKE5QViA8IDApL2xlbmd0aChOUFYpKjEwMCksIDApDQogICAgDQogICAgYnJlYWtzLnZlYyA8LSBzZXEobWluTlBWLCBtYXhOUFYrYnJlYWtzTGVuLCBieT1icmVha3NMZW4pDQogICAgDQogICAgcXVhbnQ5NSA8LSBxdWFudGlsZShOUFYsIDAuOTUpDQogICAgdGV4dC5wb3MueCA8LSBjKC10ZXh0WEFkaiwgcXVhbnQ5NS8yLCBxdWFudDk1ICsgdGV4dFhBZGopDQogICAgDQogICAgdGV4dC5sYWJlbHMgPC0gYyhwYXN0ZShwZXJjTmVnLCAiJSIsIHNlcD0iIiksIHBhc3RlKDk1IC0gcGVyY05lZywgIiUiLCBzZXA9IiIpLCAiNSUiKQ0KICAgIHRleHQubGFiZWxzIDwtIHBhc3RlKCI8IiwgdGV4dC5sYWJlbHMsICI+IikNCiAgICB0ZXh0LmNvbG9ycyA8LSBjKCJibGFjayIsICJyZWQiLCAiYmxhY2siKQ0KICAgIA0KICAgIGhpc3Qub2JqIDwtIGhpc3QoTlBWLCBicmVha3M9YnJlYWtzLnZlYywgYm9yZGVyPSJkYXJrcmVkIiwgY29sPSJyZWQiLCB4bGFiPSJOUFYgaW4gTWlsbGlvbnMiLCBtYWluPSIiLCB4bGltPXBsb3RYTGltLCBmcmVxPUZBTFNFKQ0KICAgIGFibGluZSh2PWMoMCwgcXVhbnQ5NSksIGx0eT0yKQ0KDQogICAgdGV4dFlQb3MgPC0gbWF4KGhpc3Qub2JqJGRlbnNpdHkpICsgdGV4dFlBZGoNCiAgICB0ZXh0KG1lYW5OUFYsIHN1YlRleHRBZGosIGxhYmVscz1wYXN0ZSgifCBNZWFuOiIsIHJvdW5kKG1lYW5OUFYsIDIpKSwgYWRqPTAsIGNleD0wLjgpDQogICAgdGV4dChxdWFudDk1LCBzdWJUZXh0QWRqLCBsYWJlbHM9cGFzdGUoIiBROTU6Iiwgcm91bmQocXVhbnQ5NSwgMikpLCBhZGo9MCwgY2V4PTAuOCkNCg0KICAgIHRleHQodGV4dC5wb3MueCwgdGV4dFlQb3MsIGxhYmVscz10ZXh0LmxhYmVscywgY29sPXRleHQuY29sb3JzLCBjZXg9MC44KQ0KICAgIHRleHQoLXRleHRYQWRqLCB0ZXh0WVBvcyAtIGxpbmVBZGosIGxhYmVscz0iTWluOiIsIGNleD0wLjgpDQogICAgdGV4dChxdWFudDk1K3RleHRYQWRqLCB0ZXh0WVBvcyAtIGxpbmVBZGosIGxhYmVscz0iTWF4OiIsIGNleD0wLjgpDQogICAgdGV4dCgtdGV4dFhBZGosIHRleHRZUG9zIC0gMiAqIGxpbmVBZGosIGxhYmVscz1yb3VuZChtaW5OUFYsIDIpLCBjZXg9MC44KQ0KICAgIHRleHQocXVhbnQ5NSt0ZXh0WEFkaiwgdGV4dFlQb3MgLSAyICogbGluZUFkaiwgbGFiZWxzPXJvdW5kKG1heE5QViwgMiksIGNleD0wLjgpDQogICAgDQogICAgcmV0dXJuKGhpc3Qub2JqKQ0KfQ0KYGBgDQoNCiMjIyBMb2NhbCB2YXJpYWJsZXMgZGVmaW5pdGlvbg0KDQojIyMjIFNldCBkYXRhIGZvciBXaW5kIFBvd2VyIGdlbmVyYXRpb24NCmBgYHtyfQ0KIyBCYXNlZCBvbiAoTGlyYSBhbmQgTW9pdGEgTmV0bywgMjAxNykNCndpbmQudmVsb2NpdHkgPSBjKDIuMywyLjYsMi40LDIuMSwyLjEsMi45NSwzLjUsMy42LDMuOCwzLjEsMywyLjUpIA0KDQojIEdpdmVuIGJ5IHRoZSB0ZWNobm9sb2d5IHVzZWQNCndpbmRUb1Bvd2VyIDwtIDE4NzEuMjA4MjQ3IA0KDQpwb3dlci5wcm9kdWN0aW9uIDwtIHdpbmQudmVsb2NpdHkgKiB3aW5kVG9Qb3dlcg0KDQojIyBDaGFydCAjIw0KYmFycGxvdChwb3dlci5wcm9kdWN0aW9uLCBjb2w9ImJsdWUiLCB4bGFiPSJBdmVyYWdlIE1vbnRobHkgT3V0cHV0IiwgeWxhYj0iTVdoIiwgbmFtZXMuYXJnPW1vbnRoLmFiYiwgeWxpbT1jKDAsODAwMCkpDQpgYGANCg0KIyMjIyBDb25zdGFudHMgZm9yIFBMRCBTdG9jaGFzdGljIHZhcmlhYmxlIGVzdGltYXRpb24NCg0KYGBge3J9DQojIyBQTEQgRGF0YSAjIw0KDQojIEFzIGRlZmluZWQgYnkgT05TICsgZXhwZWN0ZWQgZnV0dXJlIGluY3JlYXNlIGFkanVzdG1lbnQNClBMRE1heCA8LSAxNTAgDQoNCiMgRGVmaW5lZCBpbiBwYXBlcg0KUExEU3RhcnQgPC0gNzUgDQpQTERFdGEgPC0gMC4wODAzOCANClBMRFJldmVydGluZ01lYW4gPC0gODYuMzANClBMRFZvbGF0aWxpdHkgPC0gMC41NTcNCmBgYA0KDQojIyMjIENvbnN0YW50cyBmb3IgQlRDIFN0b2NoYXN0aWMgdmFyaWFibGUgZXN0aW1hdGlvbiwgYWxvbmcgd2l0aCBwcm9kdWN0aW9uIGNvc3RzIGFuZCBwb3dlciBjb25zdW1wdGlvbg0KDQpgYGB7cn0NCiMjIEJUQyBEYXRhICMjDQoNCiMgRGVmaW5lZCBpbiBwYXBlcg0KQlRDTXUgPC0gLTAuMDM2NiANCkJUQ1NpZ21hIDwtIDAuMjIyOA0KDQojIyBCVEMgTWluaW5nIERhdGEgIyMgDQoNCiMgQW50bWluZXIgUzE3IFBybyANCiMgVXNlZCB0byBjYWxjdWxhdGUgY29uc3VtcHRpb24gY29zdHMNCkJUQ01pbmVySGFzaCA8LSA1NioxMF4xMiAjIEhhc2hlcyBwZXIgc2Vjb25kDQpCVENNaW5lclBvd2VyIDwtIDIyMTIgIyBXYXR0cyANCiMgVXNlZCB0byBjYWxjdWxhdGUgaW52ZXN0bWVudA0KQlRDTWluZXJDb3N0IDwtIDE5MDAgIyBVU0QNCg0KIyMgQlRDIFN0b2NoYXN0aWMgUHJvY2Vzcw0KDQojIFVzZWQgaWYgQlRDU3RhcnQgaXMgc2V0IHRvICJyZWdyZXNzaW9uIg0KQlRDUmVncmVzc2lvbiA8LSAwLjA4OTQ5NzgwNyANCg0KIyBVc2VkIGlmIEJUQ1N0YXJ0IGlzIHNldCB0byAidHJpYW5ndWxhciINCkJUQ1RyaWFuZ2xlIDwtIGMoNTAwMCwgNzAwMCwgOTAwMCkgDQoNCiMgVXNlZCBpZiBCVENTdGFydCBpcyBzZXQgdG8gImRldGVybWluaXN0aWMiDQojIGFzIG9mIDIwMTktMTEtMTkgDQpCVENJbml0aWFsUHJpY2UgPC0gODEwNSANCg0KIyBVc2VkIGZvciBEZXRlcm1pbmlzdGljIGFuZCBUcmlhbmd1bGFyIHN0YXJ0cw0KIyBhcyBvZiAyMDE5LTExLTE5DQpCVENJbml0aWFsRGlmZmljdWx0eSA8LSAxMjcyMDAwNTI2NzM5MC41IA0KYGBgDQoNCiMjIyMgVmFyaWFibGVzIGZvciBjYXNoIGZsb3cgYW5kIE5QVg0KDQpgYGB7cn0NCiMjIFByb2plY3QgQ2FzaCBGbG93IERhdGEgIyMNCg0KIyBCUkwgLyBVU0QgZXhjaGFuZ2UgcmF0ZQ0KQlJMVVNERXggPC0gNCAjIFIkL1VTJA0KDQojIENvbnN0YW50cyBmb3IgV2luZCBGYXJtIC0gYmFzZWQgb24gKEZvbnRhbmV0LCAyMDEyKQ0KSW5pdGlhbEludmVzdG1lbnQgPC0gOTM3OTk0My9CUkxVU0RFeCANCkZpeGVkQ29zdHMgPC0gNTI3NTcvQlJMVVNERXggDQoNCiMgRGVmaW5lZCBpbiBwYXBlcg0KVmFyaWFibGVDb3N0cyA8LSAwLjE0ICMgJSANCldBQ0MgPC0gMC4wOCAjIEFubnVhbA0KUkYgPC0gMC4wNSAjIEFubnVhbA0KDQojIFJlZnJpZ2VyYXRpb24gY29zdHMgZm9yIEJUQyBNaW5pbmcgaW4gcGVyY2VudGFnZSBvZiB2YXJpYWJsZSBjb3N0cw0KUmVmcmlnIDwtIDAuODUgDQoNCiMgU2ltcGxpZmllZCB0YXggcmVnaW1lIA0KVGF4ZXMgPC0gMC4yNSowLjA4KzAuMDkqMC4xMiANCmBgYA0KDQoNCiMjIyBTdG9jaGFzdGljIHByb2Nlc3Nlcw0KDQojIyMjIFBMRCBEaWZmdXNpb24NCg0KYGBge3J9DQojIyBQTEQgU2VyaWVzICMjDQoNCiMgTWF0cml4IG9mIGFsbCBzZXJpZXMNClBMRC5tYXRyaXggPC0gUExEX0RpZmZ1c2lvbihQTERTdGFydCwgNzIsIE5TZXJpZXMsIFBMRFJldmVydGluZ01lYW4sIFBMRFZvbGF0aWxpdHksIFBMREV0YSwgUExETWF4KQ0KDQojIE1lYW5zIGZvciBlYWNoIHBlcmlvZCBmcm9tIGFsbCBzaW11bGF0aW9ucw0KUExELnBlcmlvZC5tZWFucyA8LSBhcHBseShQTEQubWF0cml4LCAxLCBtZWFuKSANCg0KIyBWZWN0b3Igb2YgZGV0ZXJtaW5pc3RpYyBzZXJpZXMNClBMRC5kZXRlcm1pbmlzdGljLnNlcmllcyA8LSBQTERfRGV0ZXJtaW5pc3RpYyhQTERTdGFydCwgNzIsIFBMRFJldmVydGluZ01lYW4sIFBMRFZvbGF0aWxpdHksIFBMREV0YSwgUExETWF4KQ0KDQojIyBDaGFydCAjIw0KbWF0cGxvdCgxOjczLCBjYmluZChQTEQubWF0cml4WywgMTAwMF0sIFBMRC5wZXJpb2QubWVhbnMsIFBMRC5kZXRlcm1pbmlzdGljLnNlcmllcyksIHR5cGU9J2wnLCB4bGFiPSdQZXJpb2RzJywgeWxhYj0nc2VyaWVzJykNCmxlZ2VuZCgidG9wIiwgaW5zZXQ9LjAyLCBsZWdlbmQ9YygiUmFuZG9tIFNlcmllcyIsIk1vbnRlQ2FybG8gTWVhbiIsIkRldGVybWluaXN0aWMgU2VyaWVzIiksY29sPWMoImJsYWNrIiwgInJlZCIsICJncmVlbiIpLCBsdHk9MTozLCBjZXg9MC42LCBob3Jpej1UUlVFLCBidHk9Im4iKQ0KYGBgDQoNCiMjIyMgQlRDIERpZmZ1c2lvbiANCg0KYGBge3J9DQojIyBCVEMgU3RhcnRpbmcgcG9pbnQgIyMNCg0KIyBCVEMgQ29uc3VtcHRpb24gLSB1c2VkIGZvciBEZXRlcm1pbmlzdGljIGFuZCBUcmlhbmd1bGFyIFN0YXJ0IFR5cGVzDQpCVENDb25zdW1wdGlvbkZhY3RvciA8LSAoMl4zMipCVENNaW5lclBvd2VyKS8oQlRDTWluZXJIYXNoKjM2MDAqMTIuNSoxMDAwKSAjIGtXaC9CVEMNCg0KIyBTZXQgU3RhcnQgdmFyaWFibGUgZm9yIERldGVybWluaXN0aWMgVHlwZQ0KQlRDU3RhcnREZXRlcm1pbmlzdGljIDwtIEJUQ0luaXRpYWxQcmljZSAvIChCVENDb25zdW1wdGlvbkZhY3RvciAqIEJUQ0luaXRpYWxEaWZmaWN1bHR5KQ0KDQojIFNldCBTdGFydCB2YXJpYWJsZSBmb3IgUmVncmVzc2lvbiBUeXBlDQpCVENTdGFydFJlZ3Jlc3Npb24gPC0gQlRDUmVncmVzc2lvbiAvIChCVENDb25zdW1wdGlvbkZhY3RvcioxMF44KQ0KDQojIFRyaWFuZ3VsYXIgZGlzdHJpYnV0aW9uIGZvciBCVEMgU3RhcnQgLSBpZiBUcmlhbmd1bGFyIFR5cGUgaXMgc2VsZWN0ZWQNCkJUQ1N0YXJ0VHJpYW5nbGUgPC0gcnRyaWFuZyhOU2VyaWVzLCBCVENUcmlhbmdsZVsxXSwgQlRDVHJpYW5nbGVbM10sIEJUQ1RyaWFuZ2xlWzJdKSAvIChCVENDb25zdW1wdGlvbkZhY3RvciAqIEJUQ0luaXRpYWxEaWZmaWN1bHR5KQ0KDQojIENob29zZSBCVENTdGFydCBiYXNlZCBvbiBCVENTdGFydFR5cGUgR2xvYmFsIFZhcmlhYmxlDQpCVENTdGFydCA8LSBzd2l0Y2goQlRDU3RhcnRUeXBlLCAiZGV0ZXJtaW5pc3RpYyIgPSBCVENTdGFydERldGVybWluaXN0aWMsICJ0cmlhbmd1bGFyIiA9IEJUQ1N0YXJ0VHJpYW5nbGUsICJyZWdyZXNzaW9uIiA9IEJUQ1N0YXJ0UmVncmVzc2lvbikNCg0KIyBJZiBUcmlhbmd1bGFyIFR5cGUgdGhlbiBwbG90IGRpc3RyaWJ1dGlvbg0KaWYgKEJUQ1N0YXJ0VHlwZSA9PSAidHJpYW5ndWxhciIpIGhpc3QoQlRDU3RhcnQsIGJvcmRlcj0iZGFya3JlZCIsIGNvbD0icmVkIiwgeGxhYj0iQlRDIFByaWNlL0RpZmZpY3VsdHkgU3RhcnRpbmcgUG9pbnQiLCBtYWluPSIiLCBmcmVxPUZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgQlRDIFNlcmllcyBhbmQgQ2hhcnRzICMjDQoNCiMgVmVjdG9yIG9mIEJUQyBkZXRlcm1pbmlzdGljIHNlcmllcyBmb3IgdGhlIGZpcnN0IG1pbmluZyBpbnRlcnZhbA0KQlRDLjEuZGV0ZXJtaW5pc3RpYy5zZXJpZXMgPC0gYyhyZXAoMCwgMjIpLCBCVENfRGV0ZXJtaW5pc3RpYyhCVENTdGFydCwgMjYsIEJUQ011LCBCVENTaWdtYSksIHJlcCgwLCAyNCkpDQoNCiMgVmVjdG9yIG9mIEJUQyBkZXRlcm1pbmlzdGljIHNlcmllcyBmb3IgdGhlIGZpbmFsIG1pbmluZyBpbnRlcnZhbA0KQlRDLjIuZGV0ZXJtaW5pc3RpYy5zZXJpZXMgPC0gYyhyZXAoMCwgMjIpLCBCVENfRGV0ZXJtaW5pc3RpYyhCVENTdGFydCwgMjYsIEJUQ011LCBCVENTaWdtYSksIEJUQ19EZXRlcm1pbmlzdGljKEJUQ1N0YXJ0LCAyNiwgQlRDTXUsIEJUQ1NpZ21hKVstKDE6MyldKQ0KDQojIFBsb3QgYm90aCBkZXRlcm1pbmlzdGljIHNlcmllcw0KcGxvdChCVEMuMS5kZXRlcm1pbmlzdGljLnNlcmllcywgdHlwZT0ibCIsIHhsYWI9IlBlcmlvZCIsIHlsYWI9IlByaWNlL0RpZmZpY3VsdHkiKQ0KcGxvdChCVEMuMi5kZXRlcm1pbmlzdGljLnNlcmllcywgdHlwZT0ibCIsIHhsYWI9IlBlcmlvZCIsIHlsYWI9IlByaWNlL0RpZmZpY3VsdHkiKQ0KDQojIENyZWF0ZSBhIG1hdHJpeCBmb3Igc3RvY2hhc3RpYyBzZXJpZXMgZm9yIHRoZSBmaXJzdCBtaW5pbmcgaW50ZXJ2YWwNCkJUQy4xLm1hdHJpeCA8LSBCVENfRGlmZnVzaW9uKEJUQ1N0YXJ0LCAyNiwgTlNlcmllcywgQlRDTXUsIEJUQ1NpZ21hKQ0KQlRDLjEubWF0cml4IDwtIHJiaW5kKG1hdHJpeCgwLCBucm93PTIyLCBuY29sPU5TZXJpZXMpLCBCVEMuMS5tYXRyaXgsIG1hdHJpeCgwLCBucm93PTI0LCBuY29sPU5TZXJpZXMpKQ0KDQojIE9idGFpbiB0aGUgYXZlcmFnZSBmb3IgZWFjaCBwZXJpb2QNCkJUQy4xLnBlcmlvZC5tZWFucyA8LSBhcHBseShCVEMuMS5tYXRyaXgsIDEsIG1lYW4pDQoNCiMgUGxvdCBvbmUgc2VyaWVzIG9mIHRoZSBzdG9jaGFzdGljIG1hdHJpeCBhbG9uZyB0aGUgZGV0ZXJtaW5pc3RpYyBzZXJpZXMgYW5kIHRoZSB2ZWN0b3Igb2YgYXZlcmFnZXMNCm1hdHBsb3QoMTo3MywgY2JpbmQoQlRDLjEubWF0cml4WywgMl0sIEJUQy4xLnBlcmlvZC5tZWFucywgQlRDLjEuZGV0ZXJtaW5pc3RpYy5zZXJpZXMpLCB0eXBlPSdsJywgeGxhYj0nUGVyaW9kcycsIHlsYWI9J3NlcmllcycpDQpsZWdlbmQoInRvcCIsIGluc2V0PS4wMiwgbGVnZW5kPWMoIlJhbmRvbSBTZXJpZXMiLCJNb250ZUNhcmxvIE1lYW4iLCJEZXRlcm1pbmlzdGljIFNlcmllcyIpLGNvbD1jKCJibGFjayIsICJyZWQiLCAiZ3JlZW4iKSwgbHR5PTE6MywgY2V4PTAuNiwgaG9yaXo9VFJVRSwgYnR5PSJuIikNCg0KIyBDcmVhdGUgYSBtYXRyaXggZm9yIHN0b2NoYXN0aWMgc2VyaWVzIGZvciB0aGUgZmlyc3QgbWluaW5nIGludGVydmFsDQpCVEMuMi5tYXRyaXggPC0gQlRDX0RpZmZ1c2lvbihCVENTdGFydCwgMjYsIE5TZXJpZXMsIEJUQ011LCBCVENTaWdtYSkNCkJUQy4yLm1hdHJpeCA8LSBCVEMuMi5tYXRyaXhbLWMoMTozKSwgXQ0KQlRDLjIubWF0cml4IDwtIHJiaW5kKEJUQy4xLm1hdHJpeFsxOjQ5LCBdLCBCVEMuMi5tYXRyaXgpDQoNCiMgT2J0YWluIHRoZSBhdmVyYWdlIGZvciBlYWNoIHBlcmlvZA0KQlRDLjIucGVyaW9kLm1lYW5zIDwtIGFwcGx5KEJUQy4yLm1hdHJpeCwgMSwgbWVhbikgDQoNCiMgUGxvdCBvbmUgc2VyaWVzIG9mIHRoZSBzdG9jaGFzdGljIG1hdHJpeCBhbG9uZyB0aGUgZGV0ZXJtaW5pc3RpYyBzZXJpZXMgYW5kIHRoZSB2ZWN0b3Igb2YgYXZlcmFnZXMNCm1hdHBsb3QoMTo3MywgY2JpbmQoQlRDLjIubWF0cml4WywgMl0sIEJUQy4yLnBlcmlvZC5tZWFucywgQlRDLjIuZGV0ZXJtaW5pc3RpYy5zZXJpZXMpLCB0eXBlPSdsJywgeGxhYj0nUGVyaW9kcycsIHlsYWI9J3NlcmllcycpDQpsZWdlbmQoInRvcCIsIGluc2V0PS4wMiwgbGVnZW5kPWMoIlJhbmRvbSBTZXJpZXMiLCJNb250ZUNhcmxvIE1lYW4iLCJEZXRlcm1pbmlzdGljIFNlcmllcyIpLGNvbD1jKCJibGFjayIsICJyZWQiLCAiZ3JlZW4iKSwgbHR5PTE6MywgY2V4PTAuNiwgaG9yaXo9VFJVRSwgYnR5PSJuIikNCmBgYA0KDQojIyMjIFBlcmZvcm0gdGVzdHMgb24gdGhlIEJUQyBkaWZmdXNpb24gcHJvY2Vzcw0KDQpUaGlzIGlzIHVzZWQgZm9yIGRlYnVnZ2luZyBhbmQgY2FuIHNsb3cgZG93biBjYWxjdWxhdGlvbnMuDQoNCmBgYHtyfQ0KIyBDb250cm9sZWQgYnkgR2xvYmFsIFZhcmlhYmxlIHRlc3RCVENEaWZmdXNpb24NCmlmICh0ZXN0QlRDRGlmZnVzaW9uKSB7DQogICAgdGVzdF9yZXN1bHRzXzEgPC0gY3JlYXRlX3Rlc3RzX3Jlc3VsdHMoQlRDLjEubWF0cml4WzIzOjQ5LCBdLCAiQlRDIDEiLCBCVENNdSwgQlRDU2lnbWEpDQogICAgdGVzdF9yZXN1bHRzXzIgPC0gY3JlYXRlX3Rlc3RzX3Jlc3VsdHMoQlRDLjIubWF0cml4WzUwOjczLCBdLCAiQlRDIDIiLCBCVENNdSwgQlRDU2lnbWEpDQogICAgDQogICAgcmJpbmQodGVzdF9yZXN1bHRzXzEkVGFibGUsIHRlc3RfcmVzdWx0c18yJFRhYmxlKQ0KfQ0KDQppZiAodGVzdEJUQ0RpZmZ1c2lvbikgaGlzdCh0ZXN0X3Jlc3VsdHNfMSRNdVZlYywgYm9yZGVyPSJkYXJrcmVkIiwgY29sPSJyZWQiLCB4bGFiPSJNdSBCVEMgMSIsIG1haW49IiIsIGZyZXE9RkFMU0UpDQoNCmlmICh0ZXN0QlRDRGlmZnVzaW9uKSBoaXN0KHRlc3RfcmVzdWx0c18yJE11VmVjLCBib3JkZXI9ImRhcmtyZWQiLCBjb2w9InJlZCIsIHhsYWI9Ik11IEJUQyAyIiwgbWFpbj0iIiwgZnJlcT1GQUxTRSkNCmBgYA0KDQoNCiMjIyBSZXZlbnVlIGFuZCBDYXNoIEZsb3cgQ2FsY3VsYXRpb25zDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBsb25nIHZlY3RvciBvZiBwb3dlciBwcm9kdWN0aW9uDQpwcm9kdWN0aW9uLnNlcmllcyA8LSBjKE5BLCByZXAocG93ZXIucHJvZHVjdGlvbiwgNikpDQoNCiMgTW9uZXRhcnkgcmVzdWx0cyBvZiBwcm9kdWNpbmcgZW5lcmd5IGFuZCBzZWxsaW5nIGluIFBMRA0KUExELm91dHB1dCA8LSBQTEQubWF0cml4WzI2OjczLCBdICogcHJvZHVjdGlvbi5zZXJpZXNbMjY6NzNdDQoNCiMgU2V0IEJUQyBwcm9kdWN0aW9uIGNhcA0KQlRDTWF4IDwtIChudW1iZXJCVENNaW5lcnMqQlRDTWluZXJQb3dlci8xMDAwKS9SZWZyaWcgDQoNCiMgQXV4aWxpYXJ5IHZhcmlhYmxlcyBmb3IgY2FwIG9uIEJUQyBwcm9kdWN0aW9uDQpjYXBwZWQucHJvZHVjdGlvbi5zZXJpZXMgPC0gcHJvZHVjdGlvbi5zZXJpZXMNCmNhcHBlZC5wcm9kdWN0aW9uLnNlcmllc1twcm9kdWN0aW9uLnNlcmllcyA+IEJUQ01heF0gPC0gQlRDTWF4DQoNCiMgTW9uZXRhcnkgcmVzdWx0cyBvZiBwcm9kdWNpbmcgZW5lcmd5LCBnZW5lcmF0aW5nIEJUQyBhbmQgc2VsbGluZyBpbiBzcG90IHByaWNlcyBmb3IgdGhlIGZpcnN0IGludGVydmFsDQpCVEMuMS5vdXRwdXQgPC0gQlRDLjEubWF0cml4WzI2OjQ5LCBdICogY2FwcGVkLnByb2R1Y3Rpb24uc2VyaWVzWzI2OjQ5XSAqIFJlZnJpZyAqIDEwMDANCkJUQy4xLm91dHB1dCA8LSByYmluZChCVEMuMS5vdXRwdXQsIFBMRC5vdXRwdXRbMjU6NDgsIF0pDQoNCiMgTW9uZXRhcnkgcmVzdWx0cyBvZiBwcm9kdWNpbmcgZW5lcmd5LCBnZW5lcmF0aW5nIEJUQyBhbmQgc2VsbGluZyBpbiBzcG90IHByaWNlcyBmb3IgdGhlIGZpbmFsIGludGVydmFsDQpCVEMuMi5vdXRwdXQgPC0gQlRDLjIubWF0cml4WzI2OjczLCBdICogY2FwcGVkLnByb2R1Y3Rpb24uc2VyaWVzWzI2OjczXSAqIFJlZnJpZyAqIDEwMDANCg0KIyBFbGVjdHJpY2l0eSB0aGF0IGhhcyBub3QgYmVlbiB1c2VkIGZvciBCVEMgbWluaW5nIGR1ZSB0byBwcm9kdWN0aW9uIGNhcCBjYW4gYmUgc29sZCBhdCBQTEQNCiMgQWRkcyBleHRyYSBvdXRwdXQgaWYgVFJVRQ0KaWYgKGV4dHJhUHJvZHVjdGlvbikgeyANCiAgZXh0cmEucHJvZHVjdGlvbi5zZXJpZXMgPC0gcHJvZHVjdGlvbi5zZXJpZXMgLSBjYXBwZWQucHJvZHVjdGlvbi5zZXJpZXMNCiAgZXh0cmEub3V0cHV0LjIgPC0gUExELm1hdHJpeFsyNjo3MywgXSAqIGV4dHJhLnByb2R1Y3Rpb24uc2VyaWVzWzI2OjczXQ0KICBleHRyYS5vdXRwdXQuMSA8LSByYmluZChleHRyYS5vdXRwdXQuMlsxOjI0LCBdLCBtYXRyaXgoMCwgbnJvdz0yNCwgbmNvbD1OU2VyaWVzKSkNCiAgQlRDLjEub3V0cHV0IDwtIEJUQy4xLm91dHB1dCArIGV4dHJhLm91dHB1dC4xDQogIEJUQy4yLm91dHB1dCA8LSBCVEMuMi5vdXRwdXQgKyBleHRyYS5vdXRwdXQuMg0KfQ0KYGBgDQoNCg0KIyMjIyBQcm9qZWN0IENhc2ggRmxvdyAtIHdpdGhvdXQgaW52ZXN0bWVudCBjb3N0cw0KDQpgYGB7cn0NCiMjIENhc2ggRmxvdyBSZXN1bHRzICMjDQoNClBMRC5jYXNoZmxvdyA8LSBQX2FuZF9MKFBMRC5vdXRwdXQsIFBMRC5vdXRwdXQqVmFyaWFibGVDb3N0cywgRml4ZWRDb3N0cywgVGF4ZXMsIDAgLCBUUlVFKQ0KUExELmNhc2hmbG93IDwtIHJiaW5kKG1hdHJpeCgwLCBucm93PTI1LCBuY29sPW5jb2woUExELmNhc2hmbG93KSksIFBMRC5jYXNoZmxvdykNCg0KQlRDLjEuY2FzaGZsb3cgPC0gUF9hbmRfTChCVEMuMS5vdXRwdXQsIFBMRC5vdXRwdXQqVmFyaWFibGVDb3N0cywgRml4ZWRDb3N0cywgVGF4ZXMsIDAsIFRSVUUpDQpCVEMuMS5jYXNoZmxvdyA8LSByYmluZChtYXRyaXgoMCwgbnJvdz0yNSwgbmNvbD1uY29sKEJUQy4xLmNhc2hmbG93KSksIEJUQy4xLmNhc2hmbG93KQ0KQlRDLjEuY2FzaGZsb3cgPC0gc2VsZWN0X2dyZWF0ZXIoUExELmNhc2hmbG93LCBCVEMuMS5jYXNoZmxvdykNCg0KQlRDLjIuY2FzaGZsb3cgPC0gUF9hbmRfTChCVEMuMi5vdXRwdXQsIFBMRC5vdXRwdXQqVmFyaWFibGVDb3N0cywgRml4ZWRDb3N0cywgVGF4ZXMsIDAsIFRSVUUpDQpCVEMuMi5jYXNoZmxvdyA8LSByYmluZChtYXRyaXgoMCwgbnJvdz0yNSwgbmNvbD1uY29sKEJUQy4yLmNhc2hmbG93KSksIEJUQy4yLmNhc2hmbG93KQ0KQlRDLjIuY2FzaGZsb3cgPC0gc2VsZWN0X2dyZWF0ZXIoUExELmNhc2hmbG93LCBCVEMuMi5jYXNoZmxvdykNCg0KUExELm1lYW4uY2FzaGZsb3cgPC0gYXBwbHkoUExELmNhc2hmbG93LCAxLCBtZWFuKQ0KQlRDLjEubWVhbi5jYXNoZmxvdyA8LSBhcHBseShCVEMuMS5jYXNoZmxvdywgMSwgbWVhbikNCkJUQy4yLm1lYW4uY2FzaGZsb3cgPC0gYXBwbHkoQlRDLjIuY2FzaGZsb3csIDEsIG1lYW4pDQpgYGANCg0KIyMjIyBDYXNoZmxvdyBjaGFydHMNCg0KYGBge3J9DQojIFNlbGVjdCBvbmUgc3BlY2lmaWMgc2VyaWVzIHRvIGJlIHBsb3R0ZWQNCmkgPSA0DQoNCm1hdHBsb3QoMTo3MywgY2JpbmQoUExELmNhc2hmbG93WywgaV0sIEJUQy4xLmNhc2hmbG93WywgaV0sIEJUQy4yLmNhc2hmbG93WywgaV0pLCB0eXBlPSdsJywgeGxhYj0nUGVyaW9kcycsIHlsYWI9J3NlcmllcycpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD0uMSwgbGVnZW5kPWMoIlBMRCIsIkJUQzIiLCJCVEMyKzIiKSxjb2w9YygiYmxhY2siLCAicmVkIiwgImdyZWVuIiksIGx0eT0xOjMsIGNleD0wLjYsIGhvcml6PVRSVUUsIGJ0eT0ibiIsIHRpdGxlPXBhc3RlKCJNb250ZUNhcmxvIFNlcmllcyIsaSkpDQpgYGANCg0KYGBge3J9DQojIFBsb3QgYXZlcmFnZXMNCm1hdHBsb3QoMTo3MywgY2JpbmQoUExELm1lYW4uY2FzaGZsb3csIEJUQy4xLm1lYW4uY2FzaGZsb3csIEJUQy4yLm1lYW4uY2FzaGZsb3cpLCB0eXBlPSdsJywgeGxhYj0nUGVyaW9kcycsIHlsYWI9J3NlcmllcycpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD0uMDgsIGxlZ2VuZD1jKCJQTEQiLCJCVEMyIiwiQlRDMisyIiksY29sPWMoImJsYWNrIiwgInJlZCIsICJncmVlbiIpLCBsdHk9MTozLCBjZXg9MC42LCBob3Jpej1UUlVFLCBidHk9Im4iLCB0aXRsZT0iTW9udGVDYXJsbyBBdmVyYWdlcyIpDQpgYGANCg0KIyMjIyBPYnRhaW5pbmcgRGV0ZXJtaW5pc3RpYyBSZXN1bHRzIGZvciBEZWJ1Z2dpbmcNCg0KYGBge3J9DQpQTEQub3V0cHV0LnNlcmllcyA8LSBQTEQucGVyaW9kLm1lYW5zICogcHJvZHVjdGlvbi5zZXJpZXMNClBMRC5vdXRwdXQuc2VyaWVzWzE6MjVdIDwtIDANCg0KQlRDLjEub3V0cHV0LnNlcmllcyA8LSBjKEJUQy4xLmRldGVybWluaXN0aWMuc2VyaWVzWzE6NDldKmNhcHBlZC5wcm9kdWN0aW9uLnNlcmllc1sxOjQ5XSpSZWZyaWcqMTAwMCwgUExELm91dHB1dC5zZXJpZXNbNTA6NzNdKQ0KDQpCVEMuMi5vdXRwdXQuc2VyaWVzIDwtIEJUQy4yLmRldGVybWluaXN0aWMuc2VyaWVzKmNhcHBlZC5wcm9kdWN0aW9uLnNlcmllcypSZWZyaWcqMTAwMA0KDQppZihleHRyYVByb2R1Y3Rpb24pIHsgIyBBZGRzIGV4dHJhIG91dHB1dCBpZiBUUlVFDQogICAgZXh0cmEub3V0cHV0LjIgPC0gZXh0cmEucHJvZHVjdGlvbi5zZXJpZXNbMjY6NzNdKlBMRC5kZXRlcm1pbmlzdGljLnNlcmllc1syNjo3M10NCiAgICBleHRyYS5vdXRwdXQuMSA8LSBjKGV4dHJhLm91dHB1dC4yWzE6MjRdLCByZXAoMCwgMjQpKQ0KICAgIEJUQy4xLm91dHB1dC5zZXJpZXNbMjY6NzNdIDwtIEJUQy4xLm91dHB1dC5zZXJpZXNbMjY6NzNdICsgZXh0cmEub3V0cHV0LjENCiAgICBCVEMuMi5vdXRwdXQuc2VyaWVzWzI2OjczXSA8LSBCVEMuMi5vdXRwdXQuc2VyaWVzWzI2OjczXSArIGV4dHJhLm91dHB1dC4yDQp9DQoNClBMRC5kZXRlcm1pbmlzdGljLmNhc2hmbG93IDwtIFBMRC5vdXRwdXQuc2VyaWVzKigxLVZhcmlhYmxlQ29zdHMtVGF4ZXMpLUZpeGVkQ29zdHMNCg0KQlRDLjEuZGV0ZXJtaW5pc3RpYy5jYXNoZmxvdyA8LSBCVEMuMS5vdXRwdXQuc2VyaWVzKigxLVRheGVzKS1QTEQub3V0cHV0LnNlcmllcypWYXJpYWJsZUNvc3RzLUZpeGVkQ29zdHMNCg0KQlRDLjIuZGV0ZXJtaW5pc3RpYy5jYXNoZmxvdyA8LSBCVEMuMi5vdXRwdXQuc2VyaWVzKigxLVRheGVzKS1QTEQub3V0cHV0LnNlcmllcypWYXJpYWJsZUNvc3RzLUZpeGVkQ29zdHMNCg0KIyMgQ2hhcnQgIyMNCg0KbWF0cGxvdCgxOjczLCBjYmluZChQTEQuZGV0ZXJtaW5pc3RpYy5jYXNoZmxvdywgQlRDLjEuZGV0ZXJtaW5pc3RpYy5jYXNoZmxvdywgQlRDLjIuZGV0ZXJtaW5pc3RpYy5jYXNoZmxvdyksIHR5cGU9J2wnLCB4bGFiPSdQZXJpb2RzJywgeWxhYj0nc2VyaWVzJykNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PS4wOCwgbGVnZW5kPWMoIlBMRCIsIkJUQzIiLCJCVEMyKzIiKSxjb2w9YygiYmxhY2siLCAicmVkIiwgImdyZWVuIiksIGx0eT0xOjMsIGNleD0wLjYsIGhvcml6PVRSVUUsIGJ0eT0ibiIsIHRpdGxlPSJEZXRlcm1pbmlzdGljIFNlcmllcyIpDQpgYGANCg0KDQojIyMgUHJvamVjdCBOUFYNCg0KYGBge3J9DQojIyBQcm9qZWN0IE5QViBmb3IgZWFjaCBzY2VuYXJpbyAjIw0KDQojIENhbGN1bGF0ZSBtb250aGx5IHJhdGUNClJGTW9udGhseSA8LSAoMStSRileKDAuMDgzMzMzMzMzMzMzMzMzMyktMQ0KV0FDQ01vbnRobHkgPC0gKDErV0FDQyleKDAuMDgzMzMzMzMzMzMzMzMzMyktMQ0KDQojIEludmVzdG1lbnQgZm9yIEJUQyBtaW5pbmcgaW4gYm90aCBmaXJzdCBhbmQgZmluYWwgaW50ZXJ2YWwNCkJUQ0ludmVzdG1lbnQuMSA8LSBudW1iZXJCVENNaW5lcnMqQlRDTWluZXJDb3N0KigoMStSRk1vbnRobHkpLygxK1dBQ0NNb250aGx5KSleMjINCkJUQ0ludmVzdG1lbnQuMiA8LSBudW1iZXJCVENNaW5lcnMqQlRDTWluZXJDb3N0KigoMStSRk1vbnRobHkpLygxK1dBQ0NNb250aGx5KSleNDYNCg0KIyBEdXBsaWNhdGUgZGF0YSBzZXQgdG8gYWxsb3cgZm9yIHN0YWdlIGRlYnVnZ2luZyAtIG1heSBjb3N0IG1lbW9yeQ0KTlBWLlBMRC5jYXNoZmxvdyA8LSBQTEQuY2FzaGZsb3cNCiMgSW5zZXJ0IGludmVzdG1lbnQgaW4gY2FzaCBmbG93DQpOUFYuUExELmNhc2hmbG93WzEsIF0gPC0gTlBWLlBMRC5jYXNoZmxvd1sxLCBdLUluaXRpYWxJbnZlc3RtZW50DQojIE9idGFpbiBOUFYNCk5QVi5QTEQgPC0gYXBwbHkoTlBWLlBMRC5jYXNoZmxvdywgMiwgbnB2LCByPVJGTW9udGhseSkNCg0KIyBEdXBsaWNhdGUgZGF0YSBzZXQgdG8gYWxsb3cgZm9yIHN0YWdlIGRlYnVnZ2luZyAtIG1heSBjb3N0IG1lbW9yeQ0KTlBWLkJUQy4xLmNhc2hmbG93IDwtIEJUQy4xLmNhc2hmbG93DQojIEluc2VydCBpbnZlc3RtZW50cyBpbiBjYXNoIGZsb3cNCk5QVi5CVEMuMS5jYXNoZmxvd1sxLCBdIDwtIE5QVi5CVEMuMS5jYXNoZmxvd1sxLCBdLUluaXRpYWxJbnZlc3RtZW50DQpOUFYuQlRDLjEuY2FzaGZsb3dbMjMsIF0gPC0gTlBWLkJUQy4xLmNhc2hmbG93WzIzLCBdLUJUQ0ludmVzdG1lbnQuMQ0KIyBPYnRhaW4gTlBWDQpOUFYuQlRDLjEgPC0gYXBwbHkoTlBWLkJUQy4xLmNhc2hmbG93LCAyLCBucHYsIHI9UkZNb250aGx5KQ0KDQojIER1cGxpY2F0ZSBkYXRhIHNldCB0byBhbGxvdyBmb3Igc3RhZ2UgZGVidWdnaW5nIC0gbWF5IGNvc3QgbWVtb3J5DQpOUFYuQlRDLjIuY2FzaGZsb3cgPC0gQlRDLjIuY2FzaGZsb3cNCiMgSW5zZXJ0IGludmVzdG1lbnRzIGluIGNhc2ggZmxvdw0KTlBWLkJUQy4yLmNhc2hmbG93WzEsIF0gPC0gTlBWLkJUQy4yLmNhc2hmbG93WzEsIF0tSW5pdGlhbEludmVzdG1lbnQNCk5QVi5CVEMuMi5jYXNoZmxvd1syMywgXSA8LSBOUFYuQlRDLjIuY2FzaGZsb3dbMjMsIF0tQlRDSW52ZXN0bWVudC4xDQpOUFYuQlRDLjIuY2FzaGZsb3dbNDcsIF0gPC0gTlBWLkJUQy4yLmNhc2hmbG93WzQ3LCBdLUJUQ0ludmVzdG1lbnQuMg0KIyBPYnRhaW4gTlBWDQpOUFYuQlRDLjIgPC0gYXBwbHkoTlBWLkJUQy4yLmNhc2hmbG93LCAyLCBucHYsIHI9UkZNb250aGx5KQ0KDQpgYGANCg0KIyMjIyBOUFYgZm9yIG1lYW4gcmVzdWx0cyAtIHVzZWQgZm9yIGRlYnVnZ2luZyBvbmx5DQoNCmBgYHtyfQ0KTlBWLlBMRC5tZWFuLmNhc2hmbG93IDwtIFBMRC5tZWFuLmNhc2hmbG93DQpOUFYuUExELm1lYW4uY2FzaGZsb3dbMV0gPC0gLUluaXRpYWxJbnZlc3RtZW50DQoNCk5QVi5QTEQubWVhbiA8LSBucHYoTlBWLlBMRC5tZWFuLmNhc2hmbG93LCByPVJGTW9udGhseSkNCg0KTlBWLkJUQy4xLm1lYW4uY2FzaGZsb3cgPC0gQlRDLjEubWVhbi5jYXNoZmxvdw0KTlBWLkJUQy4xLm1lYW4uY2FzaGZsb3dbMV0gPC0gLUluaXRpYWxJbnZlc3RtZW50DQpOUFYuQlRDLjEubWVhbi5jYXNoZmxvd1syM10gPC0gQlRDLjEubWVhbi5jYXNoZmxvd1syM10tQlRDSW52ZXN0bWVudC4xDQoNCk5QVi5CVEMuMS5tZWFuIDwtIG5wdihOUFYuQlRDLjEubWVhbi5jYXNoZmxvdywgcj1SRk1vbnRobHkpDQoNCk5QVi5CVEMuMi5tZWFuLmNhc2hmbG93IDwtIEJUQy4yLm1lYW4uY2FzaGZsb3cNCk5QVi5CVEMuMi5tZWFuLmNhc2hmbG93WzFdIDwtIC1Jbml0aWFsSW52ZXN0bWVudA0KTlBWLkJUQy4yLm1lYW4uY2FzaGZsb3dbMjNdIDwtIEJUQy4yLm1lYW4uY2FzaGZsb3dbMjNdLUJUQ0ludmVzdG1lbnQuMQ0KTlBWLkJUQy4yLm1lYW4uY2FzaGZsb3dbNDddIDwtIEJUQy4yLm1lYW4uY2FzaGZsb3dbNDddLUJUQ0ludmVzdG1lbnQuMg0KDQpOUFYuQlRDLjIubWVhbiA8LSBucHYoTlBWLkJUQy4yLm1lYW4uY2FzaGZsb3csIHI9UkZNb250aGx5KQ0KYGBgDQoNCiMjIyMgVGhpcmQgc2NlbmFyaW8gbm90IGluY2x1ZGVkIGluIHBhcGVyDQoNCmBgYHtyfQ0KY2hvaWNlLnZlY3RvciA8LSAoTlBWLlBMRCA+IE5QVi5CVEMuMSkNCg0KQlRDLjMuY2FzaGZsb3cgPC0gQlRDLjIuY2FzaGZsb3cNCkJUQy4zLmNhc2hmbG93WzQ5OjczLCBjaG9pY2UudmVjdG9yXSA8LSBQTEQuY2FzaGZsb3dbNDk6NzMsIGNob2ljZS52ZWN0b3JdDQoNCk5QVi5CVEMuMy5jYXNoZmxvdyA8LSBCVEMuMy5jYXNoZmxvdw0KTlBWLkJUQy4zLmNhc2hmbG93WzEsIF0gPC0gTlBWLkJUQy4zLmNhc2hmbG93WzEsIF0tSW5pdGlhbEludmVzdG1lbnQNCk5QVi5CVEMuMy5jYXNoZmxvd1syMywgXSA8LSBOUFYuQlRDLjMuY2FzaGZsb3dbMjMsIF0tQlRDSW52ZXN0bWVudC4xDQpOUFYuQlRDLjMuY2FzaGZsb3dbNDcsICFjaG9pY2UudmVjdG9yXSA8LSBOUFYuQlRDLjMuY2FzaGZsb3dbNDcsICFjaG9pY2UudmVjdG9yXS1CVENJbnZlc3RtZW50LjINCg0KTlBWLkJUQy4zIDwtIGFwcGx5KE5QVi5CVEMuMy5jYXNoZmxvdywgMiwgbnB2LCByPVJGTW9udGhseSkNCmBgYA0KDQoNCiMjIyBEaXNwbGF5aW5nIFJlc3VsdHMNCg0KIyMjIyBBdmVyYWdlIHJlc3VsdHMgLSBmb3IgZGVidWdnaW5nIHB1cnBvc2VzIG9ubHkNCg0KYGBge3J9DQprYWJsZShjYmluZCgNCiAgIlBMRCI9Zm9ybWF0X3RleHQobWVhbihOUFYuUExELm1lYW4pLCAwKSwgDQogICJCVENfMSI9Zm9ybWF0X3RleHQobWVhbihOUFYuQlRDLjEubWVhbiksIDApLCANCiAgIkJUQ18yIj1mb3JtYXRfdGV4dChtZWFuKE5QVi5CVEMuMi5tZWFuKSwgMCkNCiksIGNhcHRpb249Ik5QViBmb3IgTW9udGVDYXJsbyBBdmVyYWdlcyIpDQpgYGANCg0KIyMjIyBCYXNlIFNjZW5hcmlvIFJlc3VsdHMNCg0KYGBge3J9DQpyZXN1bHRzLm1hdHJpeC5QTEQgPSBjcmVhdGVfcmVzdWx0c190YWJsZShOUFYuUExELCAiQmFzZSIpDQptb3JlLnJlc3VsdHMubWF0cml4LlBMRCA9IGNyZWF0ZV9tb3JlX3Jlc3VsdHNfdGFibGUoTlBWLlBMRCwgIkJhc2UiKQ0KDQprYWJsZShyZXN1bHRzLm1hdHJpeC5QTEQpDQpgYGANCg0KYGBge3J9DQoNCiMjIENoYXJ0ICMjDQoNCmlmIChzYXZlUERGKSBwZGYoZmlsZT0iLi9QbG90cy9CYXNlLnBkZiIsIHdpZHRoPTgsIGhlaWdodD01KQ0KDQpQTEQuaGlzdCA8LSBjcmVhdGVfcmVzdWx0c19oaXN0KE5QVi5QTEQsIDAuNjI1LCBjKC0xMCwzMCksIDMuNSwgMC4wMDIsIC0wLjAwMzYsIDAuMDA4LCA4LCA2KQ0KDQppZiAoc2F2ZVBERikgZGV2Lm9mZigpDQpgYGANCg0KIyMjIyBGaXJzdCBTY2VuYXJpbyBSZXN1bHRzDQoNCmBgYHtyfQ0KcmVzdWx0cy5tYXRyaXguQlRDLjEgPSBjcmVhdGVfcmVzdWx0c190YWJsZShOUFYuQlRDLjEsICIyIFllYXJzIiwgTlBWLlBMRCkNCm1vcmUucmVzdWx0cy5tYXRyaXguQlRDLjEgPSBjcmVhdGVfbW9yZV9yZXN1bHRzX3RhYmxlKE5QVi5CVEMuMSwgIjIgWWVhcnMiKQ0KDQprYWJsZShyZXN1bHRzLm1hdHJpeC5CVEMuMSkNCmBgYA0KDQpgYGB7cn0NCiMjIENoYXJ0ICMjDQoNCmlmIChzYXZlUERGKSBwZGYoZmlsZT0iLi9QbG90cy8yKzBfU2NlbmFyaW8ucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTUpDQoNCkJUQy4xLmhpc3QgPC0gY3JlYXRlX3Jlc3VsdHNfaGlzdChOUFYuQlRDLjEsIDAuNjI1LCBjKC0xMCwzMCksIDMuNSwgMC4wMDIsIC0wLjAwMjIsIDAuMDA0LCA4LCA2KQ0KDQppZiAoc2F2ZVBERikgZGV2Lm9mZigpDQpgYGANCg0KIyMjIyBTZWNvbmQgU2NlbmFyaW8gUmVzdWx0cw0KDQpgYGB7cn0NCnJlc3VsdHMubWF0cml4LkJUQy4yID0gY3JlYXRlX3Jlc3VsdHNfdGFibGUoTlBWLkJUQy4yLCAiMisyIFllYXJzIiwgTlBWLlBMRCkNCm1vcmUucmVzdWx0cy5tYXRyaXguQlRDLjIgPSBjcmVhdGVfbW9yZV9yZXN1bHRzX3RhYmxlKE5QVi5CVEMuMiwgIjIrMiBZZWFycyIpDQoNCmthYmxlKHJlc3VsdHMubWF0cml4LkJUQy4yKQ0KYGBgDQoNCmBgYHtyfQ0KDQojIyBDaGFydCAjIw0KDQppZiAoc2F2ZVBERikgcGRmKGZpbGU9Ii4vUGxvdHMvMisyX1NjZW5hcmlvLnBkZiIsIHdpZHRoPTgsIGhlaWdodD01KQ0KDQpCVEMuMi5oaXN0IDwtIGNyZWF0ZV9yZXN1bHRzX2hpc3QoTlBWLkJUQy4yLCAwLjYyNSwgYygtMTAsMzApLCAzLjUsIDAuMDAyLCAtMC4wMDE3LCAwLjAwNCwgOCwgNikNCg0KaWYgKHNhdmVQREYpIGRldi5vZmYoKQ0KYGBgDQoNCiMjIyMgVGhpcmQgU2NlbmFyaW8gUmVzdWx0cyAtIG5vdCBpbmNsdWRlZCBpbiBwYXBlcg0KDQpgYGB7cn0NCkNob2ljZVNjZW5hcmlvcyA8LSBOU2VyaWVzIC0gc3VtKGNob2ljZS52ZWN0b3IpDQpQZXJjQ2hvaWNlIDwtIENob2ljZVNjZW5hcmlvcy9OU2VyaWVzKjEwMA0KDQoNCnJlc3VsdHMubWF0cml4LkJUQy4zID0gY3JlYXRlX3Jlc3VsdHNfdGFibGUoTlBWLkJUQy4zLCAiMiBvciA0IFllYXJzIiwgTlBWLlBMRCkNCm1vcmUucmVzdWx0cy5tYXRyaXguQlRDLjMgPSBjcmVhdGVfbW9yZV9yZXN1bHRzX3RhYmxlKE5QVi5CVEMuMywgIjIgb3IgNCBZZWFycyIpDQoNCmthYmxlKHJlc3VsdHMubWF0cml4LkJUQy4zLCBjYXB0aW9uPXBhc3RlKCJTY2VuYXJpb3Mgd2l0aCBDaG9pY2U6IiwgQ2hvaWNlU2NlbmFyaW9zLCAib3V0IG9mIiwgTlNlcmllcywgIigiLCBQZXJjQ2hvaWNlLCAiJSkiKSkNCmBgYA0KDQpgYGB7cn0NCiMjIENoYXJ0ICMjDQoNCmlmIChzYXZlUERGKSBwZGYoZmlsZT0iLi9QbG90cy8yKzJfU2NlbmFyaW8rQ2hvaWNlLnBkZiIsIHdpZHRoPTgsIGhlaWdodD01KQ0KDQpCVEMuMy5oaXN0IDwtIGNyZWF0ZV9yZXN1bHRzX2hpc3QoTlBWLkJUQy4zLCAwLjYyNSwgYygtMTAsMzApLCAzLjUsIDAuMDAyLCAtMC4wMDE3LCAwLjAwNCwgOCwgNikNCg0KaWYgKHNhdmVQREYpIGRldi5vZmYoKQ0KYGBgDQoNCiMjIyBBZ2dyZWdhdGVkIFJlc3VsdHMNCg0KDQpgYGB7cn0NCmthYmxlKHJiaW5kKG1vcmUucmVzdWx0cy5tYXRyaXguUExELCBtb3JlLnJlc3VsdHMubWF0cml4LkJUQy4xLCBtb3JlLnJlc3VsdHMubWF0cml4LkJUQy4zLCBtb3JlLnJlc3VsdHMubWF0cml4LkJUQy4yKSwgY2FwdGlvbj0iVGFibGUgb2YgRXh0cmEgSW5mb3JtYXRpb24iKQ0KYGBgDQoNCmBgYHtyfQ0Ka2FibGUocmJpbmQocmVzdWx0cy5tYXRyaXguUExELCByZXN1bHRzLm1hdHJpeC5CVEMuMSwgcmVzdWx0cy5tYXRyaXguQlRDLjMsIHJlc3VsdHMubWF0cml4LkJUQy4yKSwgY2FwdGlvbj0iVGFibGUgb2YgUmVzdWx0cyIpDQpgYGANCg0KDQoNCg0K